Похоже, что С++ 11 и С++ 14 рассматривают cv-квалификацию prvalues по-разному.
С++ 11 придерживается "классического" подхода, который существует со времен С++ 98: согласно 3.10/4 "неклассовые prvalues всегда имеют cv-неквалифицированные типы".
С++ 14 содержит аналогичную формулировку в 3.10/4, но она представлена в виде примечания: "[Замечание: классы и массивы prvalues могут иметь типы cv-qual, другие prvalues всегда имеют cv-неквалифицированные типы. 5. -end note]"
И в разделе 5 говорится:
6 Если первоначально значение prvalue имеет тип "cv T", где T является неквалифицированным неклассифицированным, не-массивным типом, тип выражения доводится до T до любой дальнейший анализ. 1
Эта запись 5/6 является новой в С++ 14. Теперь он рассматривает cv-квалификацию prvalues, используя тот же подход, который всегда использовался с результатами ссылочного типа (см. 5/5).
Что может быть причиной этого изменения? С++ 11 и до того, как запретить неклассовые знаки права иметь любую cv-квалификацию. С++ 14 говорит, что неклассические, non-array prvalues могут иметь cv-квалификацию, но эти cv-квалификации отбрасываются перед любым дальнейшим анализом.
Мое предположение было бы в том, что есть некоторые новые (для С++ 14) языковые особенности, которые могут как-то "видеть" cv-квалификацию prvalues при правильных обстоятельствах (до того, как будет выполнена вышеупомянутая корректировка). Они существуют? И если да, то каковы эти функции? 2
Вопрос возник из следующего контекста: представьте себе компилятор, который внутренне реализует скрытый параметр this
класса X
как переменную типа X *const
. Поскольку компилятор должен выставлять this
как prvalue, то const
не должен приводить к каким-либо проблемам в С++ 11 (или раньше), где скалярные prvalues никогда не имеют квалификацию cv. Но как насчет С++ 14? Если тот же самый компилятор предоставляет this
как значение типа X *const
, может ли это привести к проблемам?
1 По-видимому, существует противоречие между 5/6 и примечанием в 3.10/4 в С++ 14, но заметки в любом случае не являются нормативными. И я использую черновик текста.
2 Мое первоначальное предположение было decltype
. И я даже подумал, что нашел ответ, когда попытался
std::cout << std::is_same<decltype((const int) 0), const int>::value << std::endl;
в GCC, который выводит 1
. Однако, видя, что Clang и VС++ вывод 0
(и что спецификация decltype
, похоже, не поддерживает это поведение), я склонен полагать, что это всего лишь ошибка в GCC (начиная с 6.1)