оператор & lt; & lt; (поток вывода) для nullptr

Рассмотрим фрагмент общего кода C ++, который выводит в поток значения своих аргументов, если они не равны:

#define LOG_IF_NE(a, b) if(a != b) { \
std::cerr << "Failed because (" << ##a << "=" << (a) << \
") != (" << ##b << "=" << (b) << ")"; \
}

Это всего лишь пример, настоящий код генерирует исключение после записи сообщения в поток строк.
Это прекрасно работает для 2 целых, 2 указателей и т. Д. Для какого потока operator << определено.

int g_b;
int f(int a)
{
LOG_IF_NE(a, g_b);
// implementation follows
}

Проблема возникает, когда один из аргументов LOG_IF_NE является nullptr: Компилятор MSVC ++ 2013 дает error C2593: 'operator <<' is ambiguous,

int *pA;
int g()
{
LOG_IF_NE(pA, nullptr);
}

Проблема происходит потому, что nullptr имеет специальный тип и operator << не определен в STL для этого типа. Ответ на https://stackoverflow.com/a/21772973/1915854 предлагает определить operator << за std::nullptr_t

//cerr is of type std::ostream, and nullptr is of type std::nullptr_t
std::ostream& operator << (std::ostream& os, std::nullptr_t)
{
return os << "nullptr"; //whatever you want nullptr to show up as in the console
}

Это правильный способ решить проблему? Разве это не ошибка в C ++ 11 / STL, которая operator<< не определен для nullptr_t? Ожидается ли исправление в C ++ 14/17? Или это было сделано специально (следовательно, частное определение operator<< может быть подводный камень)?

2

Решение

Это LWG # 2221, который предлагает:

Очевидное решение для библиотеки — добавить nullptr_tперегрузка, которая была бы определена что-то вроде

template<class C, class T>
basic_ostream<C, T>& operator<<(basic_ostream<C, T>& os, nullptr_t)
{
return os << (void*) nullptr;
}

Мы могли бы также рассмотреть решение этой проблемы на уровне ядра: добавить специальное языковое правило, которое учитывает все случаи, когда вы пишете f(nullptr) а также f перегружен на несколько типов указателей. (Возможно, тайлбрейкер говорил, что void* является предпочтительным в таких случаях.)

Это не в C ++ 14, я не знаю, превратится ли это в C ++ 17 или нет. Это очень простая проблема, которую можно решить самостоятельно, поэтому она не имеет особого значения в плане изменений стандартов. Как вы сами сказали в вопросе — это всего лишь трехстрочная функция.

3

Другие решения

Я думаю, что это могло быть преднамеренным по той же причине, что nullptr это его собственная ценность. Чтобы молча принять это в этой ситуации, можно рассматривать как потенциальное нарушение предварительных условий и инвариантов.

nullptr это значение для инициализации указателя, чтобы определить, что он не был инициализирован. Таким образом, по этой логике фактическое ее использование в любом случае должно быть явным и документированным, чтобы предотвратить неправильное использование и потенциальные дыры в безопасности. Простая перегрузка оператора для его распечатки в любом случае не обеспечит этого.

В среде отладки (где ваш макрос будет вызывать home) гораздо больше смысла использовать утверждения с условной компиляцией, если вы проверяете инварианты и программную логику с четко определенными выходными данными для всего остального.

Это в основном сводится к точке дизайна: Обрабатывать ошибки там, где их лучше всего восстановить. Ваш макрос проверяет неравенство, но если он обнаруживает nullptr для этого макроса не имеет смысла обрабатывать эту ошибку, поэтому использование обработки исключений имеет больше смысла, поэтому проблема может быть выброшена куда-то, что может обработать и восстановить данные. nullptr, В противном случае вы позволяете программе находиться в несогласованном или небезопасном состоянии.

РЕДАКТИРОВАТЬ: Просто увидел, что вы на самом деле используете обработку исключений. Вложенная попытка / отлов, вероятно, будет оптимальной, поскольку вы можете перехватить обе ошибки там, где они могут быть обработаны.

1

По вопросам рекламы [email protected]