@GoranFlegar: я сказал, что я не адвокат по языку. Я представил обоснование, как я его вижу.
указан неверный код:
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; }
Это еще разне компилируется.