Недопустимый код:
struct foo {
struct bar;
bar x; // error: field x has incomplete type
struct bar{ int value{42}; };
};
int main() { return foo{}.x.value; }
Это совершенно очевидно, так как foo::bar
считается неполным в точке, где foo::x
определен.
Однако, похоже, существует "обходной путь", который делает то же определение класса действительным:
template <typename = void>
struct foo_impl {
struct bar;
bar x; // no problems here
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
int main() { return foo{}.x.value; }
Это работает со всеми основными компиляторами. У меня есть три вопроса:
- Действительно ли это действительно C++ код или просто причуда компиляторов?
- Если это допустимый код, существует ли в стандарте C++ абзац, касающийся этого исключения?
- Если это допустимый код, почему первая версия (без
template
) считается недействительной? Если компилятор может определить второй вариант, я не вижу причин, по которым он не смог бы определить первый.
Если я добавлю явную специализацию для void
:
template <typename = void>
struct foo_impl {};
template<>
struct foo_impl<void> {
struct bar;
bar x; // error: field has incomplete type
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
int main() { return foo{}.x.value; }
Это еще раз не скомпилируется.