为什么"template <class x>"中有"class"?

Syd*_*ius 4 c++ syntax templates

模板语句的"类"部分有什么作用?

例:

template <class T>
class Something
{
    public:
        Something(const T &something);
}
Run Code Online (Sandbox Code Playgroud)

还有什么可以去那里?我通常只看"班级".

Alf*_*ulu 8

class关键字意味着同样的事情typename大部分关键字.它们都表明T是一种类型.

关键字之间唯一的区别classtypenameclass可以用来提供类模板模板参数模板,而typename不能.考虑:

template<template <class T> class U> // must be "class"
std::string to_string(const U<char>& u)
{
  return std::string(u.begin(),u.end());
}
Run Code Online (Sandbox Code Playgroud)

唯一可以代替classtypename关键字的东西是整数类型.例如:

template<std::size_t max>
class Foo{...};
...
Foo<10> f;
Run Code Online (Sandbox Code Playgroud)

有关具体示例,请std::bitset<N>参阅标准库.


pae*_*bal 8

要定义模板参数,您需要告诉编译器参数是类型还是值.

一开始...

如果我没记错的话,C++委员会不愿意在C++语言中添加新的关键字,因此,他们决定授权以下符号:

template<int I>
int getTwice()
{
   return I * 2 ;
}

template<class T>
std::string getType(const T & t)
{
   return typeid(t).name() ;
}

void doSomething()
{
   std::cout << "25 : " << getTwice<25>() << std::endl ;
   std::cout << "5  : " << getTwice<5>() << std::endl ;

   std::cout << "type(25)   : " << getType(25) << std::endl ;
   std::cout << "type(25.5) : " << getType(25.5) << std::endl ;
   std::cout << "type(abc)  : " << getType("abc") << std::endl ;
}
Run Code Online (Sandbox Code Playgroud)

以g ++为单位的输出:

25 : 50
5  : 10
type(25)   : i
type(25.5) : d
type(abc)  : A4_c
Run Code Online (Sandbox Code Playgroud)

第一种表示法是一个值的模板.所以,我们在模板声明中有值的类型:

// "I" is the value, and "int" is the type of the value
template <int I>
Run Code Online (Sandbox Code Playgroud)

第二种表示法是未知类型的模板,并且类型未"已知"的事实由"class"关键字标记.因此,在这种情况下,"类"意味着"类型".

// "T" is a type... And "class" is the "this-is-a-type" keyword
template <class T> 
Run Code Online (Sandbox Code Playgroud)

你会注意到,使用第二种表示法,尽管有class关键字,但T可以是...一个int或另一种内置类型.但是,比起添加新关键词更好的是有这种好奇心,你不同意吗?...

糟糕!

一切都很好,直到有人写下面的代码:

template<class T> // T could be any STL container, for example a vector<char>
void printContainerData(const T & t)
{
   std::cout << "aVector:" ;

   for(T::const_iterator it = t.begin(), itEnd = t.end(); it != itEnd; ++it)
   {
      std::cout << " " << (*it) ;
   }

   std::cout << std::endl ;
}
Run Code Online (Sandbox Code Playgroud)

其中T :: const_iterator是一个类型,当然......但是,它可能是类型为T的类的静态成员,因此是一个值.编译器可能很混乱.

到底...

解决方案是告诉编译器T :: const_iterator 实际上是一个类型......这将导致这种表示法:

for(class T::const_iterator it = t.begin(), // etc.
Run Code Online (Sandbox Code Playgroud)

但是这被认为不可能/正确(类是关于类声明,不是?).于是,拖着他们的脚,他们决定一个关键字确实需要告诉编译器的符号是一个类型,而不是一个值.

我想,"类型"没有被考虑,因为将其作为关键字会破坏很多代码.所以改为使用typename.使用typename,我们可以写:

for(typename T::const_iterator it = t.begin(), // etc.
Run Code Online (Sandbox Code Playgroud)

为了保持一致性,我们应该使用:

template <typename T>
Run Code Online (Sandbox Code Playgroud)

当T应该是一个类型,而不是一个值.但出于兼容性原因,旧的表示法:

template <class T>
Run Code Online (Sandbox Code Playgroud)

仍然是授权的.

那怎么样?

eben提出了上面的答案,我想回答一个答案,因为它非常有趣:

template<template <class T> class U> // must be "class"
std::string to_string(const U<char>& u)
{
  return std::string(u.begin(),u.end());
}
Run Code Online (Sandbox Code Playgroud)

我只会评论它的"含义"(这个代码不能与我的g ++编译器上的STL容器一起使用,但这不是重点,我猜):有一刻,它对U的约束说:"U是一个在类型T上模板化的类.这是部分:

template <class T> class U
Run Code Online (Sandbox Code Playgroud)

哪个也可以写:

template <typename T> class U
Run Code Online (Sandbox Code Playgroud)

因为U实际上只是一个类(而不是内置类型),而T是一个类型,任何类型.

下一行,它说U专门针对char:

std::string to_string(const U<char>& u)
Run Code Online (Sandbox Code Playgroud)

所以,这个"通用代码"只适用于U,如果U被声明为:

template<typename T>
class U
{
   // Etc.
} ;
Run Code Online (Sandbox Code Playgroud)

并且U在char上实例化:

U<char> u ;
// etc.
to_string(u)
Run Code Online (Sandbox Code Playgroud)

但有一件事被遗忘了:Eben提出的符号可以用两种方式写成:

template<template <class T> class U>
std::string to_string(const U<char>& u)

template<template <typename T> class U>
std::string to_string(const U<char>& u)
Run Code Online (Sandbox Code Playgroud)

第二个"class"关键字本身不是"type"关键字.它是一种类型,它是T上的模板类.因此令人困惑的符号.

编写Eben代码的另一种方法是删除上面的约束,如下所示:

template<typename U>
std::string to_string(const U & u)
{
   return std::string(u.begin(),u.end());
}
Run Code Online (Sandbox Code Playgroud)

让编译器发挥其魔力:

std::list<char> myList ;
// etc.
std::cout << to_string(myList) << std:endl ;
Run Code Online (Sandbox Code Playgroud)

(Eben的代码不适用于我的g ++编译器上的"char"模板化的STL容器,例如...)