С++ 11 обратная совместимость (преобразование нулевой целочисленной константы в указатель)

Стандарт С++ допускает неявное преобразование нулевой целочисленной константы в указатель любого типа.

Следующий код недопустим, поскольку значение v здесь не является константой:

float* foo()
{
    int v = 0;
    return v;    // Error
}

Но следующий код верен:

float* foo()
{
    const int v = 0;
    return v;    // Ok in C++98 mode, error in C++11 mode
}

Вопрос: почему gcc и clang (попробовал разные версии) правильно скомпилировали код в режиме С++ 98/03, но возвращают предупреждение/ошибку при компиляции в С++ Режим 11/14 (-std=c++11)? Я попытался найти изменения в рабочем документе PDF С++ 11, но не добился успеха.

Компиляторы Intel compiler 16.0 и VS2015 не показывают ошибок и предупреждений в обоих случаях.

Ответ 1

GCC и Clang ведут себя по-другому с -std=c++11, потому что С++ 11 изменил определение константы нулевого указателя, а затем С++ 14 снова изменил его, см. Core DR 903, который изменил правила в С++ 14, так что только литералы являются константами нулевого указателя.

В С++ 03 4.10 [conv.ptr] сказал:

Константа нулевого указателя является интегральным постоянным выражением (5.19) rvalue целочисленного типа, который вычисляется до нуля.

Это позволяет использовать всевозможные выражения, если они постоянны и оцениваются до нуля. Перечисления, false, (5 - 5) и т.д. И т.д.... это часто вызывало множество проблем в коде С++ 03.

В С++ 11 говорится:

Константа нулевого указателя представляет собой целочисленное константное выражение (5.19) prvalue целочисленного типа, которое оценивается как нуль или значение класса std::nullptr_t.

И в С++ 14 говорится:

Константа нулевого указателя представляет собой целочисленный литерал (2.14.2) со значением 0 или значением класса std::nullptr_t.

Это гораздо более ограничительное правило и имеет гораздо больший смысл.