简体   繁体   English

模板中的关键字“ typename”

[英]Keyword “typename” in Templates

Following is the code and quote is from the C++ Templates by Addison Wesley : 以下是代码,引自Addison WesleyC ++模板

template <typename T> 
  class MyClass { 
      typename T::SubType * ptr; 
      … 
  };

Without typename, SubType would be considered a static member. 没有类型名,SubType将被视为静态成员。 Thus, it would be a concrete variable or object. 因此,它将是一个具体的变量或对象。 As a result, the expression T::SubType *ptr would be a multiplication of the static SubType member of class T with ptr. 结果,表达式T::SubType *ptr将是类T的静态SubType成员与ptr的乘积。

Now when I compile that code without the keyword 'typename', the error I get is this: type 'T' is not derived from type 'MyClass<T>' . 现在,当我不使用关键字'typename'编译该代码时,我得到的错误是: type 'T' is not derived from type 'MyClass<T>'

Is the compiler recognizing 'T'? 编译器识别出“ T”吗? If not, then shouldn't it be a undefined reference error? 如果不是,那么它应该不是未定义的参考错误吗? If yes, then why is this an error? 如果是,那为什么会出错?

Alright here is the complete code: 好了,这里是完整的代码:

#include <iostream>
#include <vector>

template <typename T> class MyClass 
{ 
     T::SubType * ptr; 
};

int main ()
{
    return 0;
}

The error I am getting is this: 我得到的错误是这样的:

~/Desktop/notes **g++ templates/programs/trial.cpp**
templates/programs/trial.cpp:6: error: type ‘T’ is not derived from type ‘MyClass<T>’
templates/programs/trial.cpp:6: error: expected ‘;’ before ‘*’ token

Here's another way to get the same error from g++: 这是从g ++获取相同错误的另一种方法:

class Foo { static const int x = 0;};

template <typename T> class MyClass
{
     Foo::x * ptr;
};

and another: 另一个:

class Foo { static const int x = 0;};

class MyClass
{
     Foo::x * ptr;
};

But you get a different error for this: 但是,您会得到一个不同的错误:

// class Foo { static const int x = 0;};

template <typename T> class MyClass
{
     Foo::x * ptr;
};

So: 所以:

  1. Because T is a dependent type, g++ assumes that T::SubType is an object that will be defined by the time second-phase lookup occurs. 因为T是从属类型,所以g ++假定T::SubType是将在第二阶段查找发生时定义的对象。 That's as expected, and is the usual reason that typename is required here. 符合预期,这是此处需要typename的常见原因。

  2. Even if T::SubType exists and is an object, the code is still bad, just like Foo::x *ptr is bad when Foo::x exists and is an object. 即使 T::SubType存在并且是对象,代码也仍然是错误的,就像Foo::x *ptrFoo::x存在并且是对象时Foo::x *ptr是错误的一样。 I still don't understand what the error message is about - how would it help for Foo to be derived from MyClass ? 我仍然不明白错误消息的含义-从MyClass派生Foo会对它有什么帮助? But the error message is nothing to do with templates. 但是错误消息与模板无关。

  3. "Undefined reference" is a linker error. “未定义的引用”是链接器错误。 Since this code fails to even compile, you shouldn't expect to see "undefined reference to T" anywhere. 由于此代码甚至无法编译,因此您不应期望在任何地方看到“对T的未定义引用”。

  4. I don't so far see how Foo even could be derived from MyClass . 我到目前为止还没有看到Foo甚至可以从MyClass派生而来。 I tried the following to see whether it would give a clue to the meaning of the original message, but it fails because MyClass is an incomplete type, which doesn't tell me anything about what would happen if Foo were derived from MyClass : 我尝试了以下内容,以了解是否可以了解原始消息的含义,但是失败了,因为MyClass是不完整的类型,它不能告诉我有关Foo派生自MyClass

class MyClass
{
    class Foo: public MyClass { static const int x = 0;};
     Foo::x * ptr;
};

Comeau gives far more sensible error messages for all these cases - nothing about derived types, just says that T::SubType isn't a type. 在所有这些情况下,Comeau都会给出更明智的错误消息-与派生类型无关,只是说T::SubType不是类型。 So explaining g++'s error message is going to take either knowledge or good guesses about g++ internals, and exactly where in the process of trying to parse your class template it finally gives up. 因此,解释g ++的错误消息将需要有关g ++内部的知识或猜测,而在尝试解析类模板的过程中它最终会放弃的确切位置。

Without typename, SubType would be considered a static member. 没有类型名,SubType将被视为静态成员。 Thus, it would be a concrete variable or object. 因此,它将是一个具体的变量或对象。 As a result, the expression T::SubType *ptr would be a multiplication of the static SubType member of class T with ptr. 结果,表达式T :: SubType * ptr将是类T的静态SubType成员与ptr的乘积。

This description is incorrect when applied to the example you give. 当应用于您给出的示例时,此描述不正确。 In class bodies there can be no expressions, and no constructs are parsed as a multiplication. 在类主体中,不能有表达式,也没有任何构造被解析为乘法。 However, in the C++03 syntax, there is a construct that looks as follows 但是,在C ++ 03语法中,有一个结构如下

struct Base { int a; };
struct Derived : Base {
  Base::a; // access-declaration
};

This construct was deprecated in C++03 but still supported, and means the same as the following 此构造在C ++ 03中已弃用,但仍受支持,其含义与以下相同

struct Base { int a; };
struct Derived : Base {
  using Base::a; // using-declaration
};

Because you didn't tell the compiler that T::SubType is a type and hence tell the compiler that it should parse it as the type of a pointer declaration, the compiler assumed that T::SubType is the name in an access-declaration. 因为您没有告诉编译器T::SubType是类型,因此告诉编译器它应该将其解析为指针声明的类型,所以编译器假定T::SubType是访问声明中的名称。 。 Hence it expected a semicolon directly after it, and hence it expected that T is a base class of MyClass<T> (or that MyClass<T> is a derived class of T ). 因此,它预期分号后直接它,并且因此预期T是一个基类MyClass<T>MyClass<T>派生类T )。 The error message actually has it backwards: 该错误消息实际上使它向后:

 if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname),
                                   ctype))
      {
        cp_error ("type `%T' is not derived from type `%T'",
                  IDENTIFIER_TYPE_VALUE (cname), ctype);
        ...
      }

While the macro says 虽然宏说

 /* Nonzero iff TYPE is uniquely derived from PARENT.  Under MI, PARENT can
    be an ambiguous base class of TYPE, and this macro will be false.  */
 #define UNIQUELY_DERIVED_FROM_P(PARENT, TYPE) ...

Because T::SubType is a dependent name, you need to tell the compiler that SubType is a type (not a static data member) by typing typename keyword. 因为T::SubType是从属名称,所以您需要通过键入typename关键字来告诉编译器SubType是一种类型 (不是静态数据成员)。

Read about dependent name here: 在此处阅读有关依赖名称的信息:


EDIT: 编辑:

As for your question (which you repeated in the comment): 关于您的问题(您在评论中重复了):

I think what you've posted is not the complete code. 我认为您发布的不是完整的代码。 So I cannot specifically comment on that. 因此,我无法对此发表特别评论。 Also, sometimes compilers aren't smart enough to point out the error in template code accurately. 另外,有时编译器不够聪明,无法准确指出模板代码中的错误。 So I suggested you to read about dependent name and when & why typename is required. 因此,我建议您阅读有关依赖名称的信息,以及何时以及为什么需要输入typename的信息。 Hopefully, after that you will not have any question! 希望那之后您将没有任何问题!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM