c ++非类型模板值的用途是什么?

时间:2010-11-17 21:55:01

标签: c++ templates

c ++非类型模板值有什么用?可以做些什么:

template <int I>
class MyClass
{
public:
    MyClass();
    .
    . //Use I;
    .
}

这是不能做到的:

class MyClass
{
    int I;
public:
    MyClass(int i) : I(i) {}
    .
    . //Use I
    .
}

在我看来,模板版本会为编译器创建不必要的开销,创建两个不同类型的对象,每个类方法都有单独的副本。

9 个答案:

答案 0 :(得分:8)

一个用途是模板参数推导可以用来计算我,节省了程序员的麻烦:

template<typename T, size_t N>
T *end(T (&ra)[N]) {
    return ra + N;
}

int main() {
    std::string headings[] = {"name", "dob", "address"};
    std::ostream_iterator<std::string> output(std::cout, "\t")
    std::copy(headings, end(headings), output);
    // or
    std::vector<std::string> headingvec(headings, end(headings));

}

每次要使用数组时都不会弄乱sizeof

我很确定它的最初动机是像std::bitset这样的类模板,正如其他人所提到的那样。

答案 1 :(得分:6)

使用模板,您可以执行此操作:

template <int I>
class MyClass
{
   int array[I];
}

答案 2 :(得分:3)

创建单独的类型实际上是一个有用的idom(google“int to type idiom”)。但除此之外,模板版本允许编译在编译时知道数字的值,而不是运行时。这意味着可以使用一组不同的可能优化。真正的可能性是巨大的,这个功能基本上使c ++模板本身就是一种完整的计算语言。

对于常见用法的基本示例,假设您要创建一个在编译时已知固定大小的容器。没有非类型模板参数,你无法实现它。像这样:

array<int, 10> x; // create an object 10 int's big

答案 3 :(得分:2)

可以使用这种结构的东西是无穷无尽的。一个基本的例子是boost :: array,它指定通过非类型模板参数的大小。不可能以任何其他方式(聚合类型,堆栈上的内容)执行相同的操作。

答案 4 :(得分:2)

不同之处在于模板版本在编译时被扩展,因此整数编译成隐式常量;在非模板化版本中,整数在运行时仍然存在。在模板化版本中,MyClass<1>MyClass<2>是两种不同的,不兼容的类型,并且尝试将一个分配给另一个将产生编译器错误。

一个典型的例子是通用矢量类(数学矢量,而不是std::vector),其中大多数方法的工作方式相同,无论矢量的维数如何(添加2空间矢量和4空间矢量正是相同的操作),但有些仅针对特殊情况定义(交叉产品仅针对3空间和7空间向量定义)。如果要将向量的维度存储在成员变量中,则每次需要使用可能不兼容的参数执行操作时都必须执行运行时检查(例如,向4空间向量添加2空格向量),并且你必须在运行时处理结果错误。

答案 5 :(得分:2)

使用非类型模板参数,你真的可以做很多事情。一个这样的例子,通常与模板元编程相关(参见Andrei Alexandrescu关于此的书:“现代C ++设计”)是一个在编译时计算阶乘的模板类。像

这样的东西
template<int N>
class factorial
{
 public:
     enum { value = N * factorial<N-1>::value };
}

然后你可以完全专门化你的阶乘类为0,所以它实际上在某个地方结束:

template<>
class factorial<0>
{
 public:
     enum { value = 1 };
}

然后,您可以使用此类在编译时计算一些因子,如下所示:

int f4 = factorial<4>::value; // f4 will be 24 at compile time. Neat!

这可能不是最有用的例子,但是你可以了解情况。

你可以在维基百科上找到这个例子,你也可以在这里阅读更多关于这个主题的内容。

干杯。

答案 6 :(得分:1)

一种用途是metaprogramming

一个例子(从维基百科无耻地窃取)是一个在编译时计算数字能力的模板:

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}

答案 7 :(得分:0)

如果你想为类型定义“常量”,它会很有用......

例如..

template <typename _foo, int _id>
class field
{
public:

  int id() { return _id; }

};

现在当你声明一个字段实例时,你可以编码它的id ...

field<int, 10> _f1;
field<double, 11> _f2;

等。为什么这有用?考虑第三方使用的协议,例如交换(比如FAST / FIX等)

答案 8 :(得分:0)

以身作则。

此刻,我正在开发一个Trie结构(顺便提一下,如果有人知道一个好的实现......)。

Trie基本上是一棵N-ary树,第一层基本上是完整的,然后越深入你越深入(这不是结构的合适,只是大多数词典有更短的结构)单词比较长的单词)。

我正在考虑使用这个模板专长来最小化分配的节点数。以非模板化的方式,它会:

class Node3; // contains N Node2
class Node2; // contains N Node1
class Node1; // contains N Node0
class Node0; // contains N Node
class Node;  // contains N POINTERS to Node

使用我做的模板:

template <size_t L> class Node; // contains N Node<L-1>
template <> class Node<0>;      // contains N Node
class Node;                     // contains N POINTERS to Node

为自己省去了编写宏或反复复制代码的无聊任务。