何时需要“typename”关键字?

可能重复:
官方,什么是typename?
我在哪里以及为什么必须放置模板和typename关键字?

考虑下面的代码:

template<class K>
class C {
    struct P {};
    vector<P> vec;
    void f();
};

template<class K> void C<K>::f() {
    typename vector<P>::iterator p = vec.begin();
}

为什么在这个例子中需要“typename”关键字? 是否有其他情况下必须指定“typename”?


简短的回答:每次引用一个嵌套的名字,这个名字是一个依赖名字,也就是嵌套在一个未知参数的模板实例中。

长答案:C ++中有三层实体:值,类型和模板。 所有这些都可以有名称,并且名称本身并不会告诉你它是哪一层实体。 相反,关于名称实体性质的信息必须从上下文中推断出来。

无论何时推断都不可能,你必须指定它:

template <typename> struct Magic; // defined somewhere else

template <typename T> struct A
{
  static const int value = Magic<T>::gnarl; // assumed "value"

  typedef typename Magic<T>::brugh my_type; // decreed "type"
  //      ^^^^^^^^

  void foo() {
    Magic<T>::template kwpq<T>(1, 'a', .5); // decreed "template"
    //        ^^^^^^^^
  }
};

在这里,名称Magic<T>::gnarl Magic<T>::brughMagic<T>::brughMagic<T>::kwpq必须被解释,因为不可能说明:由于Magic是模板,类型的本质Magic<T>依赖于T - 例如,可能存在与主模板完全不同的特化。

使Magic<T>::gnarl成为独立名称的原因是我们在模板定义中,其中T未知。 如果我们使用Magic<int> ,这将是不同的,因为编译器知道(你保证!) Magic<int>的完整定义。

(如果你想自己测试一下,下面是你可以使用的Magic的一个示例定义,为简明起见,请constexprconstexpr中使用constexpr ;如果你有一个旧的编译器,可以随意将静态成员常量声明改为旧的样式的pre-C ++ 11表单)。

template <typename T> struct Magic
{
  static const T                    gnarl;
  typedef T &                       brugh;
  template <typename S> static void kwpq(int, char, double) { T x; }
};
template <> struct Magic<signed char>
{
  // note that `gnarl` is absent
  static constexpr long double brugh = 0.25;  // `brugh` is now a value
  template <typename S> static int kwpq(int a, int b) { return a + b; }
};

用法:

int main()
{
  A<int> a;
  a.foo();

  return Magic<signed char>::kwpq<float>(2, 3);  // no disambiguation here!
}

typename关键字是必需的,因为iteratorP上的依赖类型。 编译器无法猜测iterator是指一个值还是一个类型,所以它会假定它的值,除非你叫出typename 。 只要有一个依赖于模板参数的类型,就需要它,在类型或值都是有效的上下文中。 例如,由于基类必须是类型,因此不需要基类typename

在同一主题上,有一个template关键字,用于让编译器知道某些依赖名称是模板函数而不是值。


只要类型名称取决于模板参数,就需要typename关键字(因此编译器可以在第一次通过时没有完整符号表的情况下“知道”标识符的语义(类型或值))。


不具有相同的含义,并且不太常见,使用泛型模板参数时,单独的typename关键字也可能很有用:http://ideone.com/amImX

#include <string>
#include <list>
#include <vector>

template <template <typename, typename> class Container,
          template <typename> class Alloc = std::allocator>
struct ContainerTests 
{
    typedef Container<int, Alloc<int> > IntContainer;
    typedef Container<std::string, Alloc<int> > StringContainer;
    //
    void DoTests()
    {
        IntContainer ints;
        StringContainer strings;
        // ... etc
    }
};

int main()
{
    ContainerTests<std::vector> t1;
    ContainerTests<std::list>   t2;

    t1.DoTests();
    t2.DoTests();
}
链接地址: http://www.djcxy.com/p/37145.html

上一篇: When is the "typename" keyword necessary?

下一篇: Difference of keywords 'typename' and 'class' in templates?