Jos*_*son 14 c++ templates dependent-name c++11
struct Bar {
template<typename>
void baz() {
}
};
template<typename>
struct Foo {
Bar bar;
Foo() {
bar.baz<int>();
}
};
int main() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这段代码编译得很好(在GCC 4.7中),但如果我将调用前缀bar.baz<int>()加上this->,则baz成为需要消除歧义的从属名称template.
bar.baz<int>(); // OK
this->bar.baz<int>(); // error
this->bar.template baz<int>(); // OK
Run Code Online (Sandbox Code Playgroud)
当然this->bar只能参考Bar bar,其成员baz显然是模板?为什么添加this->使代码对编译器不明确?
ps最初,bar是一个需要消除歧义的基类模板的数据成员this->,但为了这个问题,我简化了示例.
this->bar.baz<int>(); // error
Run Code Online (Sandbox Code Playgroud)
上面的语句在 的定义内格式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:
一个类型是依赖的,如果它是
模板参数,
...
[ simple- ] template-id,其中模板名称是模板参数,或者任何模板参数是依赖类型或依赖于类型或值的表达式,
[T是依赖类型, 也是Foo<T>。]
C++03/N3690 14.6.2.2/2:
this如果封闭成员函数的类类型是相关的,则该函数是类型相关的。
[由于Foo<T>是依赖类型,因此其成员定义中的表达式this是类型依赖的。]
两个标准的 14.6.2.2 开头均为:
除下述情况外,如果任何子表达式是类型相关的,则表达式是类型相关的。
C++03 只有三类简单的表达式,并具有更准确的描述:
主要表达式(this和查找名称)
指定自己类型的表达式(如强制转换和新表达式)
具有常量类型的表达式(如文字 和sizeof)。
第一个类别在 C++03 14.6.2.2/3 中定义:
如果id表达式包含以下内容,则它是类型相关的:
使用依赖类型声明的标识符,
依赖的模板ID ,
指定依赖类型的转换函数 ID,
包含命名依赖类型的类名的嵌套名称说明符。
因此,单独的表达式bar不是依赖的:它是一个标识符和一个id-expression,但以上都不适用。
但this->bar不是id-expression,或者在任何其他 C++03 异常中,因此我们必须遵循子表达式规则。由于子表达式this与类型相关,因此包含表达式this->bar也与类型相关。
但事实上,正如您所注意到的,this->bar在解析模板定义时可以知道 的类型,而无需实例化任何模板参数。它被声明为主模板的成员,因此名称必须绑定到该成员声明。模板专业化可能会导致Foo<T>::bar未声明或以不同的方式声明,但在这种情况下,根本不会使用主模板,并且Foo()该专业化的当前定义将被忽略。这就是为什么 C++11 定义了“当前实例化”的概念,并将其用于类型相关表达式的传染性的进一步例外。
N3690 14.6.2.1/1:
名称指的是当前实例化,如果它是
在类模板、类模板的嵌套类、类模板的成员或类模板的嵌套类的成员的定义中,类模板或嵌套类的注入类名称
在主类模板或主类模板成员的定义中,类模板的名称后跟主模板的模板参数列表(如下所述)
<>(或等效的模板别名专业化),...
[第一个项目符号表示Foo当前实例化。第二个表示Foo<T>当前实例化。在此示例中,两者命名相同的类型。]
14.6.2.1/4:
名称是当前实例化的成员,如果它是
一种非限定名称,在查找时至少引用当前实例化类或其非依赖基类的一个成员。
一个合格的 ID,其中...
一个id-expression ,表示类成员访问表达式中的成员,其中对象表达式的类型是当前实例化,并且 id -expression查找时至少引用当前实例化的类的至少一个成员或其非依赖基类。
[第一个项目符号bar单独表示是当前实例化的成员。第三个项目符号表示this->bar是当前实例化的成员。]
最后,C++11 为类型相关表达式添加了第四类规则,用于成员访问。14.6.2.2/5:
如果类成员访问表达式引用当前实例化的成员并且所引用成员的类型是相关的,或者类成员访问表达式引用未知特化的成员,则该表达式是类型相关的。
this->bar确实引用当前实例化的成员,但Bar所引用成员的类型不相关。因此 nowthis->bar不依赖于类型,并且bazin 中的名称this->bar.baz在模板定义期间作为非依赖名称进行查找。template之前不需要关键字baz。