Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么关键字是“quot;typename";是否需要在限定的从属名称之前,而不是在限定的独立名称之前?_C++_Templates_Typename - Fatal编程技术网

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);
    }
};