Основные реализации C++, похоже, имеют совершенно иное
представление по этому поводу. Что делать с обоснованностью следующих 4
утверждений?
struct a {
template
constexpr a() { (T&&)0; }
};
struct b : a {};
template
constexpr int f() { return (T&&)0; }
template
constexpr int v = (T&&)0;
static_assert(sizeof(a{})); // #1 - clang ok, gcc nope, msvc ok
static_assert(sizeof(b{})); // #2 - clang nope, gcc ok, msvc ok
static_assert(sizeof(f())); // #3 - clang ok, gcc nope, msvc ok
static_assert(sizeof(v)); // #4 - clang ok, gcc ok, msvc nope
Очевидно, что формирование ссылки на void (т.е. (T&&)0, где T = void)
не является допустимым выражением. Однако такое выражение на самом деле никогда
не вычисляется в этом примере программы, поскольку оно является лишь частью
определения невычисленного операнда. Чем на самом деле объясняется такое
расхождение в поведении всех этих компиляторов?
Демо
Ошибка Clang сообщение:
:3:23: error: cannot form a reference to 'void'
3 | constexpr a() { (T&&)0; }
| ^
:14:24: note: in instantiation of function template specialization
'a::a' requested here
14 | static_assert(sizeof(b{}));
| ^
Сообщение об ошибке GCC:
: In instantiation of 'constexpr a::a() [with T = void]':
:13:24: required from here
13 | static_assert(sizeof(a{}));
| ^
:3:21: error: forming reference to void
3 | constexpr a() { (T&&)0; }
| ^~~~~~
: In instantiation of 'constexpr int f() [with T = void]':
:15:23: required from here
15 | static_assert(sizeof(f()));
| ~~^~~
:8:28: error: forming reference to void
8 | constexpr int f() { return (T&&)0; }
| ^~~~~~
Сообщение об ошибке MSVC:
(11): error C7683: you cannot create a reference to 'void'
(11): note: the template instantiation context (the oldest one first) is
(16): note: see reference to variable template 'const int v'
being compiled
Подробнее здесь: https://stackoverflow.com/questions/792 ... defintions