首页 文章

模板中的关键字“typename”

提问于
浏览
1

以下是代码和引用来自Addison Wesley的C模板:

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

如果没有typename,SubType将被视为静态成员 . 因此,它将是一个具体的变量或对象 . 因此,表达式T :: SubType * ptr将是类T的静态SubType成员与ptr的乘法 .

现在当我编译没有关键字'typename'的代码时,我得到的错误是: type ‘T’ is not derived from type ‘MyClass<T>’ .

编译器是否识别'T'?如果没有,那么它不应该是未定义的引用错误吗?如果是,那为什么这是一个错误?

好的,这里是完整的代码:

#include <iostream>
#include <vector>

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

int main ()
{
    return 0;
}

我得到的错误是这样的:

~/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

3 回答

  • 3

    这是从g获得相同错误的另一种方法:

    class Foo { static const int x = 0;};
    
    template <typename T> class MyClass
    {
         Foo::x * ptr;
    };
    

    另一个:

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

    但是你得到了一个不同的错误:

    // class Foo { static const int x = 0;};
    
    template <typename T> class MyClass
    {
         Foo::x * ptr;
    };
    

    所以:

    • 因为T是从属类型,g假定 T::SubType 是将在第二阶段查找发生时定义的对象 . 这是预期的,这是通常的原因,这里需要 typename .

    • 即使 T::SubType 存在并且是一个对象,代码仍然很糟糕,就像 Foo::x *ptr 存在 Foo::x 并且是一个对象时一样 . 我仍然不明白错误信息是什么 - 如何从 MyClass 派生 Foo 会有什么帮助?但错误消息与模板无关 .

    • “未定义的引用”是链接器错误 . 由于此代码甚至无法编译,因此您不应期望在任何地方看到“未定义的T引用” .

    • 我到目前为止还没看到 Foo 甚至可以从 MyClass 派生出来 . 我尝试了以下内容,看看它是否会提供原始消息的含义的线索,但它失败了因为 MyClass 是一个不完整的类型,它没有告诉我如果 Foo 是从 MyClass 派生的将会发生什么:

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

    Comeau为所有这些案例提供了更明智的错误消息 - 没有任何关于派生类型的信息,只是说 T::SubType isn 't a type. So explaining g++'的错误信息将会对g内部结构采取任何知识或良好猜测,并确切地说在尝试解析你的内容的过程中它终于放弃了类模板 .

  • 2

    如果没有typename,SubType将被视为静态成员 . 因此,它将是一个具体的变量或对象 . 因此,表达式T :: SubType * ptr将是类T的静态SubType成员与ptr的乘法 .

    应用于您提供的示例时,此描述不正确 . 在类体中,不能有表达式,也不会将构造解析为乘法 . 但是,在C 03语法中,有一个结构如下所示

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

    此构造在C 03中已弃用但仍受支持,并且与以下内容相同

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

    因为您没有告诉编译器 T::SubType 是一个类型,因此告诉编译器它应该将其解析为指针声明的类型,编译器假定 T::SubType 是访问声明中的名称 . 因此它预期在它之后直接有一个分号,因此它期望 TMyClass<T> 的基类(或者 MyClass<T>T 的派生类) . 错误消息实际上是向后的:

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

    虽然宏说

    /* 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) ...
    
  • 0

    因为 T::SubType 是从属名称,所以您需要通过键入 typename keyword告诉编译器 SubType 是一个类型(不是静态数据成员) .

    在此处阅读依赖名称:


    编辑:

    至于你的问题(你在评论中重复):

    我认为你足够聪明,可以准确地指出模板代码中的错误 . 所以我建议你阅读有关依赖名称以及何时以及为何需要 typename . 希望在那之后你不会有任何问题!

相关问题