请考虑以下示例
template <typename A> struct S
{
A a;
void foo() {}
};
template <typename T> void bar()
{
S<void> *p = 0;
}
template <typename T> void baz()
{
S<void>{}.foo();
}
template <typename T> void qux()
{
S<void> s{};
}
int main()
{
}
功能模板 bar
, baz
和 qux
故意不进行实例化 .
baz
的定义无法在GCC和Clang中编译"obvious"原因 - S<void>
是 S
的无效专门化 . 但是,在这种情况下,哪种语言规则正在起作用?
-
一方面,
S<void>
不依赖于baz
的模板参数,成员访问要求它完成,这会触发S<void>
的实例化,这会失败 . 诊断是必需的 . -
另一方面,我们有"if no valid specialization can be generated for a non-instantiated template, the code is ill-formed"的一揽子规则 . 这使得
baz
的定义不合理 . 但是,不需要诊断 .
更具体地说,我是否正确地假设(如#1所示)上述对非实例化 baz
的 S<void>
的引用需要实例化 S<void>
?两个编译器都乐于接受 bar
的定义这一事实支持了这一假设,该定义并未实例化 S<void>
.
然而,上述编制者对他们的处理方式有所不同--Clang抱怨,而GCC接受它没有任何投诉 . 这是其中一个编译器的错误吗?在这种情况下是否需要诊断?或者我错误地假设#1在这里工作?如果#2是诊断的基础,那么编译器之间的差异是可以接受的 .
2 回答
S<void>{}
和S<void> s{}
都在需要实例化S<void>
的上下文中使用,这样的实例化由于成员类型void
不完整而格式不正确 .相关报价为
[temp.inst]/1
:和
[temp.arg]/6
:另一方面,
baz
和quz
都是格式错误的NDR[temp.res]/8
:对于
baz
和qux
,包含S<void>
的表达式的有效性只能通过S的实例化来完成 . 但是,编译器不会在任何实例化之前执行此验证[temp.res]/8