以下为无效代码:
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; }
This works https://godbolt.org/g/8vjFNk与所有主要编译器。
对此我有三个问题:
- 这确实是有效的 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; }
又是一次编译失败 https://godbolt.org/g/3NsNhA.
真正的答案可能是 ́\_(ツ)_/́,但目前可能还可以,因为模板很神奇,但在等待其他一些核心问题解决之前,可能更明确的是不行。
首先,主要问题当然是[class.mem]/14 http://eel.is/c++draft/class#mem-14:
非静态数据成员不得具有不完整的类型。
这就是您的非模板示例格式错误的原因。然而,根据[温度点]/4 http://eel.is/c++draft/temp.point#4:
对于类模板专业化、类成员模板专业化或类模板的类成员的专业化,如果该专业化因从另一个模板专业化中引用而被隐式实例化,如果引用专业化的上下文取决于在模板参数上,并且如果在实例化封闭模板之前未实例化专业化,实例化点紧邻封闭模板的实例化点之前。否则,此类专门化的实例化点立即位于引用该专门化的名称空间范围声明或定义之前。
这表明foo_impl<void>::bar
被实例化before foo_impl<void>
,因此它在类型的非静态数据成员所在的点完成bar
被实例化。所以也许没关系。
However、核心语言问题1626 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1626 and 2335 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2335处理关于完整性和模板的不完全相同但仍然相当相似的问题,两者都表明希望使模板案例与非模板案例更加一致。
从整体上看,这一切意味着什么?我不知道。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)