为什么这种情况不正确(这是合乎逻辑的)
template <typename T>
struct Der: public Base
{
typedef int T;
T val;
};
,但那个案子是对的吗?
struct Base
{
typedef int T;
};
template <typename T>
struct Der: public Base
{
T val;
};
标准14.6.1 / 7说:
在类模板的定义中或出现在模板定义之外的此类模板的成员的定义中,对于不依赖于模板参数的每个基类(14.6.2),如果基类的名称或基类成员的名称与template-parameter的名称相同,基类名称或成员名称隐藏模板参数名称(3.3.7)。
为什么这里不含糊?
答案 0 :(得分:15)
根据[temp.local] / 6:
,第一个例子不正确template-parameter 不得在其范围内重新声明(包括嵌套范围)。
然而,在
template <typename T>
struct Der: public Base
{
T val;
};
T
被继承自Base
的名称隐藏 - 按照您的报价指定。
[..] if 基类名称或成员名称 基类与模板参数的名称相同,即 基类名称或成员名称隐藏模板参数名称 (3.3.7)强>
即,成员val
的类型为int
。 Demo
答案 1 :(得分:2)
一般来说,标准试图确保一个类型的含义 给定的范围是相同的。
如果我们假装允许typedef,那么请考虑以下val1
,val2
和val3
的类型?
template <typename T>
struct Der: public Base
{
void f1() {
T val1; // What is the type of 'val1'?
}
T val2; // What is the type of 'val2'?
typedef int T;
T val3; // What is the type of 'val3'?
};
具有模板参数类型T的唯一变量是 'VAL2'。
这是因为该标准要求该类的所有成员都在f1
的“范围内”。这就是成员函数可以引用稍后在类体中定义的成员变量的原因。
同样的问题也可以通过typedef来证明:
typedef int T;
struct S
{
T x;
typedef float T;
T y;
};
同样,如果这是合法的,那么用于T
声明的x
将引用::T
,而用于T
的{{1}}会引用y
to typedef S::T
。
ISO 3.3.7 / 1中的标准涵盖了这一点:
以下规则描述了在类中声明的名称范围。
...
2)在S类中使用的名称N应在其上下文中引用相同的声明,并在完成的S范围内重新评估。违反此规则不需要诊断。
答案 2 :(得分:1)
因为第二个是不明确的:
您可能不关心或知道超类中有typedev int T
,但您刚刚引入T
作为模板参数,这清楚表明您在使用时指的是它T
中的Der
。