另一位语言律师。
对于以下代码,无论是否存在A<int>
的显式实例化:
clang 3.0在typename
和Type1
的声明中需要Type3
,但在Type2
的声明中不要求。
gcc 4.8.1在typename
的声明中需要Type1
,但在Type2
或Type3
的声明中不需要。
struct C
{
int f1();
static int f2();
int m;
};
template<int i>
struct S
{
typedef int Type;
};
template<typename T>
struct B : C
{
};
template<typename T>
struct A : B<T>
{
void f()
{
typedef typename S<sizeof(C::f1())>::Type Type1; // typename required
typedef S<sizeof(C::f2())>::Type Type2; // typename not required
typedef typename S<sizeof(C::m)>::Type Type3; // typename not required?
}
};
template struct A<int>;
我认为
typename
的声明中需要Type1
,因为调用非静态成员的隐含对象参数是(*this)
,其类型是依赖的。参见[over.call.func]:
按照此逻辑,由于成员是静态的,因此在
typename
的声明中不需要Type2
。 typename
的声明中也不需要Type3
,因为该表达式不是对非静态成员的调用。我已经读完了:Where and why do I have to put the "template" and "typename" keywords?
..并通过[temp.dep.type]和[temp.dep.expr]中的规则。在确定表达式是否从属时,我看不到任何指定非静态成员函数名称是否应给予特殊处理的东西。标准是否规定了这一点?
编辑:删除了基于[class.mfct.non-static]的类成员访问表达式转换的讨论-Casey的答案对此进行了更详细的讨论。
最佳答案
C
是在阶段1查找期间通过非限定名称查找解析的非依赖性名称。 C::f1
和C::f2
是在模板查找的第一阶段中也通过合格名称查找来解析的非依赖性名称。无论C
是否是A
的基础,这都是事实。
问题中引用的[class.mfct.non-static]文本似乎来自C++ 03。 C++ 11文本(9.3.1 / 3)读为:
可以在可以使用C::f1
的上下文中评估this
,因此C::f1
转换为(*this).C::f1
。由于B<T>
明确取决于模板参数,因此(*this).C::f1
是14.6.2.1/5中未知特化的成员。 [标准使用此术语“未知特化的成员”来表示表达,这些表达可能表示模板的某些特化的成员,但并非对所有特化都是可证明的。 ]
由于(*this).C::f1
表示未知特化的成员,因此它是14.6.2.2/5中与类型相关的类成员访问表达式。通过扩展,(*this).C::f1()
根据14.6.2.2/1是类型相关的。 sizeof((*this).C::f1())
然后根据14.6.2.3/2与值相关。 S<sizeof((*this).C::f1())>
-一个具有与值相关的自变量表达式的简单模板ID-则是14.6.2.1/8中的相关类型。
由于S<sizeof((*this).C::f1())>
是依赖的,S<sizeof((*this).C::f1())>::Type
取决于14.6.2 / 1“...如果id-expression的unqualified-id是其中任何模板参数都依赖于模板参数的模板ID,则”。最后,但并非最不重要的一点是,14.6 / 2要求使用关键字typename
来指示从属名称引用一种类型:typename S<sizeof((*this).C::f1())>::Type
我认为这就是推理的全部过程。
编辑:这个答案似乎是错误的。短语“可能评估”在3.2 / 2一个定义规则[basic.def.odr]中定义:
示例中的C::f1
无疑是C::f1()
的子表达式,它是按照5.3.3 / 1 Sizeof [expr.sizeof]估算的sizeof
操作数。
编辑:我相信表达式qualified-id()
当前不是,但是当(1)它出现在类模板的成员函数内并且(2)qualified-id是一个不相关的名称,表示一个重载集时,应将其视为类型相关的类的非静态成员函数的类型;(3)this
的类型是依赖的。确定表达式的类型需要按照13.3.1.1.1 / 3的重载解析,当this
在作用域内而不确定this
所引用的类的类型时,这是不可能的。
我认为可以通过在14.6.2.1/5 [temp.dep.type]中添加以下项目符号来实现:
关于c++ - 当模板参数包含非静态成员的名称时,是否需要 'typename'?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17642624/