为什么“template <class x =”“>”?</class>中有“class”

时间:2008-12-08 05:31:09

标签: c++ templates syntax

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

示例:

template <class T>
class Something
{
    public:
        Something(const T &something);
}

还有什么可以去那里?我通常只看“课”。

3 个答案:

答案 0 :(得分:8)

class关键字与大多数typename关键字的含义相同。它们都表明T是一种类型。

关键字classtypename之间的唯一区别是class可用于向模板提供类模板模板参数,而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());
}

您可以替代classtypename关键字的唯一其他事项是整数类型。例如:

template<std::size_t max>
class Foo{...};
...
Foo<10> f;

有关具体示例,请查看标准库中的std::bitset<N>

答案 1 :(得分: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 ;
}

以g ++表示哪些输出:

25 : 50
5  : 10
type(25)   : i
type(25.5) : d
type(abc)  : A4_c

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

// "I" is the value, and "int" is the type of the value
template <int I>

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

// "T" is a type... And "class" is the "this-is-a-type" keyword
template <class T> 

你会注意到,使用第二种表示法,尽管有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 ;
}

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

最后......

解决方案是告诉编译器T :: const_iterator是真的一个类型......这会带有这种表示法:

for(class T::const_iterator it = t.begin(), // etc.

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

我认为,

“type”没有被考虑,因为将其作为关键字会破坏很多代码。所以改为使用typename。使用typename,我们可以写:

for(typename T::const_iterator it = t.begin(), // etc.

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

template <typename T>

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

template <class T>

仍然有权。

那怎么样?

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

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

template <class T> class U

也可写:

template <typename T> class U

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

下一行,它说U专门用于char:

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

因此,如果U被声明为:

,则此“通用代码”仅适用于U.
template<typename T>
class U
{
   // Etc.
} ;

U在一个char上实例化了:

U<char> u ;
// etc.
to_string(u)

但有一件事被遗忘了: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)

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

另一种写Eben代码的方法,删除上面的约束,就像:

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

让编译器发挥其魔力:

std::list<char> myList ;
// etc.
std::cout << to_string(myList) << std:endl ;

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

答案 2 :(得分:4)

您还可以使用以下作为模板参数:

  • 任何整数类型short, int, long, bool
  • 指向对象或函数的指针
  • 对象或函数的引用
  • 指向成员对象或成员函数的指针

一些例子:

template<typename T, int N=4, bool Flag>
class myClass { /*...*/ };

template<typename T, const int& Reference, myClass * Pointer>
class someClass { /*...*/ };

template<typename T, int (T::*MemberFunctionPtr)(int, int)>
class anotherClass { /*...*/ };