C++ 什么时候需要“typename”关键字?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7923369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:42:57  来源:igfitidea点击:

When is the "typename" keyword necessary?

c++templatessyntaxtypename

提问by Martin

Possible Duplicate:
Officially, what is typename for?
Where and why do I have to put the template and typename keywords?

可能的重复:
正式地说,typename 是什么?
在哪里以及为什么必须放置模板和类型名称关键字?

consider the code below:

考虑下面的代码:

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

Why is the "typename" keyword necessary in this example? Are there any other cases where "typename" must be specified?

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

回答by Kerrek SB

Short answer: Whenever referring to a nested name that is a dependent name, i.e. nested inside a template instance with unknown parameter.

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

Long answer: There are three tiers of entities in C++: values, types, and templates. All of those can have names, and the name alone doesn't tell you which tier of entity it is. Rather, the information about the nature of a name's entity must be inferred from the context.

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

Whenever this inference is impossible, you have to specify it:

每当此推理不可能时,您必须指定它:

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"
    //        ^^^^^^^^
  }
};

Here the names Magic<T>::gnarl, Magic<T>::brughand Magic<T>::kwpqhad to be expliciated, because it is impossible to tell: Since Magicis a template, the very natureof the type Magic<T>depends on T-- there may be specializations which are entirely different from the primary template, for example.

此处的名称Magic<T>::gnarl, Magic<T>::brughandMagic<T>::kwpq必须加以说明,因为无法判断: 因为Magic是模板,所以类型的本质Magic<T>取决于T——例如,可能存在与主模板完全不同的特化。

What makes Magic<T>::gnarla dependent name is the fact that we're inside a template definition, where Tis unknown. Had we used Magic<int>, this would be different, since the compiler knows (you promise!) the full definition of Magic<int>.

产生Magic<T>::gnarl依赖名称的原因是我们在模板定义中,其中的位置T是未知的。如果我们使用Magic<int>,情况会有所不同,因为编译器知道(你保证!) 的完整定义Magic<int>

(If you want to test this yourself, here's a sample definition of Magicthat you can use. Pardon the use of constexprin the specializaation for brevity; if you have an old compiler, feel free to change the static member constant declaration to the old-style pre-C++11 form.)

(如果你想自己测试这个,这里有一个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; }
};

Usage:

用法:

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

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

回答by K-ballo

The typenamekeyword, is needed because iteratoris a dependent type on P. The compiler can't guess if iteratorrefers to a value or a type, so it assume its a value unless you yell typename. It's needed whenever there is a type dependent on a template argument, in a context that either types or values would be valid. For instance, as base classes typenameis not needed since a base class must be a type.

typename关键字,需要因为iterator是上一个依赖型P。编译器无法猜测iterator是指一个值还是一个类型,因此它假定它是一个值,除非您大喊typename. 在类型或值都有效的上下文中,只要存在依赖于模板参数的类型,就需要它。例如,typename不需要as 基类,因为基类必须是一种类型。

On the same subject, there is a templatekeyword used to let the compiler know that some dependent name is a template function instead of a value.

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

回答by sehe

The typename keyword is needed whenever a type name depends on a template parameter, (so the compiler can 'know' the semantics of an identifier (typeor value) without having a full symbol table at the first pass).

每当类型名称依赖于模板参数时,都需要 typename 关键字(因此编译器可以“知道”标识符(类型)的语义,而无需在第一次传递完整的符号表)。



Not in the same meaning, and a bit less common, the lone typename keywordcan also be useful when using generic template parameters: http://ideone.com/amImX

含义不同,而且不太常见,lone 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();
}