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:
一个类型是依赖的,如果它是
[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 表达式包含以下内容,则它是类型相关的:
所以唯一的表达式bar
是不依赖的:它是一个标识符和一个id-expression,但以上都不适用。
But this->bar
is 不是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:
一个名称是当前实例化的成员,如果它是
[第一个项目符号bar
单独说是当前实例化的成员。第三个项目符号说this->bar
是当前实例化的成员。]
最后,C++11 为类型相关表达式添加了第四类规则,用于成员访问。14.6.2.2/5:
如果表达式引用当前实例化的成员并且被引用成员的类型是依赖的,或者类成员访问表达式引用未知特化的成员,则类成员访问表达式是类型相关的。
this->bar
确实引用了当前实例化的成员,但Bar
被引用成员的类型不相关。所以 nowthis->bar
不依赖于类型,在模板定义过程中查找baz
in的名称作为非依赖名称。之前不需要关键字this->bar.baz
。template
baz