C++ 为什么关键字是“quot;typename";是否需要在限定的从属名称之前,而不是在限定的独立名称之前?
我(想我)明白为什么这里需要C++ 为什么关键字是“quot;typename";是否需要在限定的从属名称之前,而不是在限定的独立名称之前?,c++,templates,typename,C++,Templates,Typename,我(想我)明白为什么这里需要typename: class A { static int iterator; class iterator { [...] }; [...] }; template <class T> void foo() { typename T::iterator* iter; [...] } 有人能解释一下吗 编辑: 编译器对后者没有问题的原因,我发现在一条评论中得到了很好的回答: 在A::iterat
typename
:
class A
{
static int iterator;
class iterator
{
[...]
};
[...]
};
template <class T>
void foo() {
typename T::iterator* iter;
[...]
}
有人能解释一下吗
编辑: 编译器对后者没有问题的原因,我发现在一条评论中得到了很好的回答:
在
A::iterator
的情况下,我不明白为什么编译器不会将其与静态int迭代器
混淆xcrypt
@xcrypt,因为它知道
A::iterator
s是什么,并且可以根据使用方式选择哪一个–Seth Carnegie
我认为,编译器在限定的依赖名之前需要
typename
的原因在Kerrek SB接受的答案中得到了很好的回答。请务必阅读关于该答案的评论,尤其是iammilind的评论:
“T::A*x;,对于T::A是类型而T::A是值的两种情况,此表达式都可以为真。如果A是类型,则它将导致指针声明;如果A是值,则它将导致乘法。因此,单个模板对于两种不同的类型具有不同的含义,这是不可接受的。”因为编译器在模板实例化之前不知道
t::iterator
是什么,所以它不知道iterator
是类变量、类型、函数还是什么。你需要告诉它,它是一个类型,使用<代码>类型名< /C> > .< /P> < P> C++中的名称可以涉及三个不同的实体层次:值、类型和模板。
void foo() {
A::iterator* iter;
[...]
}
现在我们遇到了麻烦:什么是T::A
?如果T=Foo
,则T::A=int
,这是一种类型,一切正常。但是当T=struct{chara;}
,那么T::A
是一个没有意义的值
因此,编译器要求您告诉它T::A
和T::B
和T::C
应该是什么。如果你什么也不说,它被认为是一个值。如果您说typename
,它是一个typename;如果您说template
,它是一个模板:
template <typename T> struct Bar
{
T::A x;
};
模板结构栏
{
typename T::A x;//啊,很好,有条理的typename
void foo()
{
int a=T::B;//假定值,确定
T::template cz;//命令模板
z、 狼吞虎咽(a*x);
}
};
次要检查,如
T::B
是否可转换为int
,a
和x
是否可以相乘,以及C
是否真的有成员函数gobble
,都将推迟到您实际实例化模板时进行。但是,名称是表示值、类型还是模板的规范对于代码的语法正确性至关重要,必须在模板定义过程中立即提供。因为在非模板foo中,您正在执行有效的乘法运算(假设您在使用之前声明了iter
)。尝试忽略星号,您将得到一个编译器错误。int隐藏该类
typename关键字不能阻止隐藏。只有gcc错误地实现了它。因此,如果您试图用
A
作为类型实例化函数模板,那么您将得到一个编译错误,因为在teer-typenake之后指定的名称将引用任何标准一致性编译器上的非类型。@AndrewMarshall为什么要更改标记?那么,模板元编程不是正确的术语吗?我认为“模板”可能意味着不同的东西,比如一些预定义的文本等?没有模板元编程涉及到在编译时使用模板生成代码,这在这里是不做的。如果你愿意的话,你可以读更多关于精神错乱的书related@AndrewMarshall那么你是说template void foo(){[…]}
在代码中的某个地方使用时不会在编译时生成代码?@awoodland也被称为“Bjarne从未打算做的事情”:Pand在另一种情况下,它确实知道我们想要什么?我不认为编译器在实例化之前不知道它是什么的危害,这不是模板背后的全部原理吗?@xcrypt是的,因为它知道什么是A
,因此知道什么是A::iterator
。至于它为什么这样工作,这是因为语言的设计者选择了这样做。他们不是等待,而是让程序员告诉他们应该是什么。@xcrypt它不知道t
是什么,但是它确实需要知道T::iterator
在语句/表达式中的实际角色是什么。在A::iterator
的情况下,我不明白为什么编译器不会将其与static int iterator
?@xcrypt混淆,因为它知道A::iterator
都是什么,并且可以根据它的方式选择哪一个usedPretty是一个很好的解释吗?我只有一个问题:你是说编译器必须这样做,还是说这只是为了让编写编译器的人更容易理解?我对编译器知之甚少,但我认为编译器应该有可能了解自己?当模板在实例化时被编译时(在代码的某些部分使用时),它可能只会给出一个错误?@xcrypt:这是绝对必要的。你还会怎么解析X::AX::C
?@Kerrek:嗯,你不会,就像MSVC一样:P(免责声明:我不知道MSVC是否会解析它。)@KerrekSB copy-paste,如果它不正确,显示一个错误?但是,我可以看到,这种方法无法检查在实例化之前模板的定义是否有意义,但应该是可能的,不是吗?@ XLIPT,有几个方面,编译器需要考虑。例如,T::A*x
,此表达式适用于以下两种情况:T::A
是类型,T::A
是值。如果A
是一种类型,则
template <typename T> struct Bar
{
T::A x;
};
template <typename T> struct Bar
{
typename T::A x; // ah, good, decreed typename
void foo()
{
int a = T::B; // assumed value, OK
T::template C<int> z; // decreed template
z.gobble(a * x);
}
};