C++ 我必须在哪里以及为什么要把;模板";及;typename";关键词?

C++ 我必须在哪里以及为什么要把;模板";及;typename";关键词?,c++,templates,typename,c++-faq,dependent-name,C++,Templates,Typename,C++ Faq,Dependent Name,在模板中,我必须将typename和template放在从属名称上的位置和原因是什么? 到底什么是从属名称 我有以下代码: template <typename T, typename Tail> // Tail will be a UnionNode too. struct UnionNode : public Tail { // ... template<typename U> struct inUnion { // Q: where

在模板中,我必须将
typename
template
放在从属名称上的位置和原因是什么?
到底什么是从属名称

我有以下代码:

template <typename T, typename Tail> // Tail will be a UnionNode too.
struct UnionNode : public Tail {
    // ...
    template<typename U> struct inUnion {
        // Q: where to add typename/template here?
        typedef Tail::inUnion<U> dummy; 
    };
    template< > struct inUnion<T> {
    };
};
template <typename T> // For the last node Tn.
struct UnionNode<T, void> {
    // ...
    template<typename U> struct inUnion {
        char fail[ -2 + (sizeof(U)%2) ]; // Cannot be instantiated for any U
    };
    template< > struct inUnion<T> {
    };
};
template//Tail也将是一个UnionNode。
结构UnionNode:公共尾部{
// ...
模板结构inUnion{
//问:在这里哪里添加typename/模板?
typedef-Tail::inUnion-dummy;
};
模板<>结构单元{
};
};
模板//用于最后一个节点Tn。
结构联合节点{
// ...
模板结构inUnion{
char fail[-2+(sizeof(U)%2)];//无法为任何U实例化
};
模板<>结构单元{
};
};
我遇到的问题在
typedef Tail::inUnion dummy
行中。我相当肯定,
inUnion
是一个依赖的名称,VC++完全正确地扼杀了它。
我还知道我应该能够在某个地方添加
模板
,告诉编译器inUnion是一个模板id。但是具体在哪里呢?然后,它是否应该假设inUnion是一个类模板,即
inUnion
命名一个类型而不是一个函数?

typedef typename Tail::inUnion dummy;
typedef typename Tail::inUnion<U> dummy;
然而,我不确定您对inUnion的实现是否正确。如果我理解正确的话,这个类不应该被实例化,因此“fail”选项卡永远不会失败。也许最好用一个简单的布尔值指示类型是否在并集中

template <typename T, typename TypeList> struct Contains;

template <typename T, typename Head, typename Tail>
struct Contains<T, UnionNode<Head, Tail> >
{
    enum { result = Contains<T, Tail>::result };
};

template <typename T, typename Tail>
struct Contains<T, UnionNode<T, Tail> >
{
    enum { result = true };
};

template <typename T>
struct Contains<T, void>
{
    enum { result = false };
};
模板结构包含;
模板
结构包含
{
枚举{result=Contains::result};
};
模板
结构包含
{
枚举{result=true};
};
模板
结构包含
{
枚举{result=false};
};
附:看一看

PS2:请看,尤其是在Andrei Alexandrescu的书中:现代C++设计< /P> <代码> Type f Type Ne: 然而,我不确定您对inUnion的实现是否正确。如果我理解正确的话,这个类不应该被实例化,因此“fail”选项卡永远不会失败。也许最好用一个简单的布尔值指示类型是否在并集中

template <typename T, typename TypeList> struct Contains;

template <typename T, typename Head, typename Tail>
struct Contains<T, UnionNode<Head, Tail> >
{
    enum { result = Contains<T, Tail>::result };
};

template <typename T, typename Tail>
struct Contains<T, UnionNode<T, Tail> >
{
    enum { result = true };
};

template <typename T>
struct Contains<T, void>
{
    enum { result = false };
};
模板结构包含;
模板
结构包含
{
枚举{result=Contains::result};
};
模板
结构包含
{
枚举{result=true};
};
模板
结构包含
{
枚举{result=false};
};
附:看一看

PS2:请看,尤其是在Andrei Alexandrescu的书中:现代C++设计

(参阅)

< >为了分析C++程序,编译器需要知道某些名称是否为类型。以下示例说明:

t * f;
这应该如何解析?对于许多语言,编译器不需要知道名称的含义就可以解析代码,并且基本上知道一行代码的作用。然而,C++中,根据代码< > <代码>的含义,可以产生很大不同的解释。如果它是一个类型,那么它将是指针
f
的声明。然而,如果它不是一个类型,它将是一个乘法。因此,C++标准在第(3/7)段:

有些名称表示类型或模板。通常,每当遇到名称时,在继续解析包含该名称的程序之前,必须确定该名称是否表示这些实体之一。确定这一点的过程称为名称查找

如果
t
引用模板类型参数,编译器将如何找出名称
t::x
引用的是什么
x
可以是可以相乘的静态int数据成员,也可以是可以生成声明的嵌套类或typedef如果名称具有此属性(在知道实际模板参数之前无法查找),则称为从属名称(它“取决于”模板参数)。

您可能建议等待用户实例化模板:

让我们等到用户实例化模板,然后再找出
t::x*f的真正含义

这将起作用,并且实际上是标准允许的一种可能的实现方法。这些编译器基本上将模板的文本复制到内部缓冲区中,并且仅当需要实例化时,才解析模板并可能检测定义中的错误。但是,其他实现没有因为模板作者的错误而困扰模板的用户(可怜的同事!),而是选择尽早检查模板,并在实例化之前尽快给出定义中的错误

因此,必须有一种方法告诉编译器某些名称是类型,而某些名称不是类型

“typename”关键字 答案是:我们决定编译器应该如何解析它。如果
t::x
是一个依赖名称,那么我们需要用
typename
作为前缀,告诉编译器以某种方式解析它。该标准规定为(14.6/2):

模板声明或定义中使用的、依赖于模板参数的名称是 假定不命名类型,除非适用的名称查找找到类型名称或名称是限定的 通过关键字typename

有许多名称不需要
typename
,因为编译器可以通过模板定义中适用的名称查找,找出如何解析构造本身-例如使用
T*f,当
T
是类型模板参数时。但是对于
t::x*f
要成为一个声明,它必须写成
typename t::x*f。如果省略关键字并且名称被视为非类型,但当实例化发现它表示类型时,编译器会发出通常的错误消息。萨米特
boost::function< int() > f;
namespace boost { int function = 0; }
int main() { 
  int f = 0;
  boost::function< int() > f; 
}
t::template f<int>(); // call a function template
this->template f<int>(); // call a function template
template <typename T, typename Tail>
struct UnionNode : public Tail {
    // ...
    template<typename U> struct inUnion {
        typedef typename Tail::template inUnion<U> dummy;
    };
    // ...
};
typename t::template iterator<int>::value_type v;
 template <typename T>
 struct derive_from_Has_type : /* typename */ SomeBase<T>::type 
 { };
 template <typename T>
 struct derive_from_Has_type : SomeBase<T> {
    using SomeBase<T>::template type; // error
    using typename SomeBase<T>::type; // typename *is* allowed
 };
template<typename T>
struct A {
  typedef int result_type;

  void f() {
    // error, "this" is dependent, "template" keyword needed
    this->g<float>();

    // OK
    g<float>();

    // error, "A<T>" is dependent, "typename" keyword needed
    A<T>::result_type n1;

    // OK
    result_type n2; 
  }

  template<typename U>
  void g();
};
struct B {
  typedef int result_type;
};

template<typename T>
struct C { }; // could be specialized!

template<typename T>
struct D : B, C<T> {
  void f() {
    // OK, member of current instantiation!
    // A::result_type is not dependent: int
    D::result_type r1;

    // error, not a member of the current instantiation
    D::questionable_type r2;

    // OK for now - relying on C<T> to provide it
    // But not a member of the current instantiation
    typename D::questionable_type r3;        
  }
};
template<>
struct C<int> {
  typedef bool result_type;
  typedef int questionable_type;
};
void h() {
  typename A<T>::questionable_type x;
}
struct B { void f(); };
struct A : virtual B { void f(); };

template<typename T>
struct C : virtual B, T {
  void g() { this->f(); }
};

int main() { 
  C<A> c; c.g(); 
}
template<typename T>
struct test {
    using type = T; // no typename required
    using underlying_type = typename T::type // typename required
};
template<typename T>
struct test {
    // typename required
    using type = typename std::conditional<true, const T&, T&&>::type;
    // no typename required
    using integer = std::conditional<true, int, float>::type;
};
template<typename T>
struct test {
    template<typename U>
    void get() const {
        std::cout << "get\n";
    }
};

template<typename T>
void func(const test<T>& t) {
    t.get<int>(); // error
}
template<class T> void f_tmpl () { T::foo * x; /* <-- (A) */ }
struct X { typedef int       foo;       }; /* (C) --> */ f_tmpl<X> ();
struct Y { static  int const foo = 123; }; /* (D) --> */ f_tmpl<Y> ();
template<class T> void g_tmpl () {
   SomeTrait<T>::type                   foo; // (E), ill-formed
   SomeTrait<T>::NestedTrait<int>::type bar; // (F), ill-formed
   foo.data<int> ();                         // (G), ill-formed    
}
template<class T> void g_tmpl () {
   typename SomeTrait<T>::type foo;                            // (G), legal
   typename SomeTrait<T>::template NestedTrait<int>::type bar; // (H), legal
   foo.template data<int> ();                                  // (I), legal
}
namespace N {
  template<class T>
  struct X { };
}
         N::         X<int> a; // ...  legal
typename N::template X<int> b; // (K), legal
typename template    X<int> c; // (L), ill-formed
                    // .------- the base-specifier-list
  template<class T> // v
  struct Derived      : typename SomeTrait<T>::type /* <- ill-formed */ {
    ...
  };
  struct Base {
    template<class T>
    struct type { };
  };

  struct Derived : Base {
    using Base::template type; // ill-formed
    using Base::type;          // legal
  };
template< typename T > void foo( T& x, std::string str, int count )
{
    // these names are looked up during the second phase
    // when foo is instantiated and the type T is known
    x.size(); // dependant name (non-type)
    T::instance_count ; // dependant name (non-type)
    typename T::iterator i ; // dependant name (type)
      
    // during the first phase, 
    // T::instance_count is treated as a non-type (this is the default)
    // the typename keyword specifies that T::iterator is to be treated as a type.

    // these names are looked up during the first phase
    std::string::size_type s ; // non-dependant name (type)
    std::string::npos ; // non-dependant name (non-type)
    str.empty() ; // non-dependant name (non-type)
    count ; // non-dependant name (non-type)
}
class A { public: typedef int type; static const int val { 1 }; };
class B { public: typedef float type; static const int val { 2 }; };
template<typename T> class C {};
template<int I> class D {};
template<typename T> class X {
    T::type v;                                  // OK
    T::type f(T::type arg) { return arg; }      // OK
    T::type g(double arg) { return static_cast<T::type>(arg); } // OK
    // C<T::type> c1;                           // error
    D<T::val> d;                                // OK (as has always been)
    C<typename T::type> c2;                     // OK (old style)
    typedef T::type mytype;                     // OK
    using mytypeagain = T::type;                // OK
    C<mytype> c3;                               // OK (via typedef / using)
};
X<A> xa;
X<B> xb;
template <class T>
struct DependentType
{
  typename T::type a;
  using Type=typename T::type;
};

template <class T>
struct DependentTemplate
{
  // template function
  template <class U>
  static void func() {}

  // template class
  template <class U>
  struct ClassName{};
};


template <class T1, class T2>
void foo()
{
  // 3 ways to call a dependent template function
  DependentTemplate<T1>::template func<T2>();
  DependentTemplate<T1>().template func<T2>();
  (new DependentTemplate<T1>())->template func<T2>();

  // You need both typename and template to reference a dependent template class
  typename DependentTemplate<T1>::template ClassName<T2> obj;
  using Type=typename DependentTemplate<T1>::template ClassName<T2>;
}