什么时候需要"typename"关键字?

Mar*_*tin 50 c++ syntax templates 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();
}
Run Code Online (Sandbox Code Playgroud)

为什么此示例中需要"typename"关键字?是否还有其他必须指定"typename"的情况?

Ker*_* SB 70

简短回答:每当引用一个依赖名称的嵌套名称时,即嵌套在具有未知参数的模板实例中.

答案很简单: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"
    //        ^^^^^^^^
  }
};
Run Code Online (Sandbox Code Playgroud)

这里的名称Magic<T>::gnarl,Magic<T>::brugh并且Magic<T>::kwpq必须被解释,因为它是不可能分辨的:因为Magic是模板,类型的本质Magic<T>取决于T- 例如,可能存在与主模板完全不同的特化.

是什么让Magic<T>::gnarl一个从属名称是一个事实,即我们是一个模板定义,其中里面T是未知的.如果我们使用Magic<int>,这将是不同的,因为编译器知道(你保证!)的完整定义Magic<int>.

(如果你想自己测试一下,这里有Magic你可以使用的示例定义.请原谅constexpr专业化中的使用以简洁;如果你有一个旧的编译器,请随意将静态成员常量声明更改为旧式前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; }
};
Run Code Online (Sandbox Code Playgroud)

用法:

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

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


K-b*_*llo 10

typename关键字,需要因为iterator是上一个依赖型P.编译器无法猜测是否iterator引用了值或类型,因此除非你大喊,否则它会假设它是一个值typename.只要存在依赖于模板参数的类型,在类型或值有效的上下文中就需要它.例如,typename由于基类必须是类型,因此不需要基类.

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


seh*_*ehe 8

只要类型名称依赖于模板参数,就需要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();
}
Run Code Online (Sandbox Code Playgroud)