以下是无效代码:
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; }
这个 works与所有主要编译器。 我对此有三个问题:
- 这确实是有效的 C++ 代码,还是只是编译器的怪癖?
- 如果是有效代码,C++ 标准中是否有段落处理此异常?
- 如果是有效代码,为什么第一个版本(没有
模板
)被认为是无效的?如果编译器可以找出第二个选项,我看不出它无法找出第一个选项的原因。
如果我为 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; }
再次fails to compile .
最佳答案
真正的答案可能是¯\_(ツ)_/¯,但目前可能还可以,因为模板很神奇,但在其他一些核心问题解决之前,它可能更明确地不行。
首先,主要问题当然是[class.mem]/14 :
Non-static data members shall not have incomplete types.
这就是您的非模板示例格式错误的原因。然而,根据 [temp.point]/4 :
For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
这表明 foo_impl<void>::bar
被实例化之前 foo_impl<void>
,因此它在类型为 bar
的非静态数据成员处完成。被实例化。所以也许没关系。
然而,核心语言问题 1626和 2335处理关于完整性和模板的不完全相同但仍然非常相似的问题,并且都指向希望使模板案例与非模板案例更加一致。
从整体上看,这一切意味着什么?我不确定。
关于c++ - 类中不允许不完整类型,但类模板中允许使用不完整类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50202718/