struct Bar {
template<typename>
void baz() {
}
};
template<typename>
struct Foo {
Bar bar;
Foo() {
bar.baz<int>();
}
};
int main() {
return 0;
}
这段代码编译得很好(在 GCC 4.7 中),但是如果我在调用前加上 bar.baz<int>()
与 this->
, baz
成为需要用 template
消除歧义的从属名称.
bar.baz<int>(); // OK
this->bar.baz<int>(); // error
this->bar.template baz<int>(); // OK
当然this->bar
只能引用Bar bar
, 其成员 baz
显然是一个模板?为什么要添加this->
让这个代码对编译器产生歧义?
附言原来,bar
是需要用 this->
消除歧义的基类模板的数据成员,但为了这个问题,我已经简化了这个例子。
最佳答案
this->bar.baz<int>(); // error
上述声明,在 template<typename T> Foo<T>::Foo()
的定义中, 格式正确,如果启用了 C++11 模式或 C++1y 模式,则应被接受。但根据 C++03,它在技术上是错误的。
两个标准都同意 this
是一个依赖于类型的表达式:
C++03 14.6.2.1/1; N3690 14.6.2.1/8:
A type is dependent if it is
a template parameter,
...
a [simple-]template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent,
[ T
是依赖类型,Foo<T>
也是.]
C++03/N3690 14.6.2.2/2:
this
is type-dependent if the class type of the enclosing member function is dependent.
[自 Foo<T>
是依赖类型,表达式 this
在其成员定义中是依赖于类型的。]
这两个标准都从 14.6.2.2 开始:
Except as described below, an expression is type-dependent if any subexpression is type-dependent.
C++03 只有三种简单的表达方式,描述更准确:
主要表达式(
this
和查找名称)指定自己类型的表达式(如强制转换和新表达式)
具有常量类型的表达式(如文字和
sizeof
)。
第一类在C++03 14.6.2.2/3中定义:
An id-expression is type-dependent if it contains:
an identifier that was declared with a dependent type,
a template-id that is dependent,
a conversion-function-id that specifies a dependent type,
a nested-name-specifier that contains a class-name that names a dependent type.
所以孤独的表达bar
不依赖:它是一个标识符和一个id-expression,但以上都不适用。
但是this->bar
不是id-expression,或者在任何其他C++03 异常中,所以我们必须遵循子表达式规则。由于子表达式 this
是类型相关的,包含表达式 this->bar
也是依赖于类型的。
但事实上,正如您所注意到的,this->bar
的类型可以在解析模板定义时知道,而无需实例化任何模板参数。它被声明为主模板的成员,因此名称必须绑定(bind)到该成员声明。模板特化可能会使 Foo<T>::bar
未声明或以不同的方式声明,但在这种情况下,根本不会使用主模板,而当前定义的 Foo()
对于该特化,将被忽略。这就是为什么 C++11 定义了“当前实例化”的概念并将其用于类型相关表达式的传染性的进一步异常(exception)。
N3690 14.6.2.1/1:
A name refers to the current instantiation if it is
in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name of the class template or nested class
in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in
<>
(or an equivalent template alias specialization),...
[第一个项目符号是 Foo
是当前的实例化。第二个说Foo<T>
是当前的实例化。在本例中,两者命名相同的类型。]
14.6.2.1/4:
A name is a member of the current instantiation if it is
An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof.
A qualified-id in which ...
An id-expression denoting the member in a class member access expression for which the type of the object expression is the current instantiation, and the id-expression, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof.
[第一个项目符号是 bar
单独是当前实例化的成员。第三个子弹说this->bar
是当前实例化的成员。]
最后,C++11 为类型相关表达式添加了第四类规则,用于成员访问。 14.6.2.2/5:
A class member access expression is type-dependent if the expression refers to a member of the current instantiation and the type of the referenced member is dependent, or the class member access expression refers to a member of an unknown specialization.
this->bar
确实引用了当前实例化的成员,但类型为 Bar
被引用的成员不依赖。所以现在this->bar
不依赖于类型,名称 baz
在 this->bar.baz
在模板定义期间作为非依赖名称查找。 template
baz
之前不需要关键字.
关于c++ - 为什么只有在符合 "this"条件时,数据成员的模板函数才是从属名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24588207/