模板 < 无符号 int N > 是什么意思?

在声明模板时,我习惯于使用这种代码:

template <class T>

但是 在这个问题中,他们使用:

template <unsigned int N>

我检查了它是否编译。但这意味着什么?它是非类型参数吗?如果是这样,我们怎么能有一个没有任何类型参数的模板?

123250 次浏览

完全可以对整数而不是类型建立类模板。我们可以将模板值赋给一个变量,或者以其他方式操作它,比如使用任何其他整数字面值:

unsigned int x = N;

实际上,我们可以创建在编译时求值的算法(来自 维基百科) :

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
}

您根据“无符号 int”对类进行模板化。

例如:

template <unsigned int N>
class MyArray
{
public:
private:
double    data[N]; // Use N as the size of the array
};


int main()
{
MyArray<2>     a1;
MyArray<2>     a2;


MyArray<4>     b1;


a1 = a2;  // OK The arrays are the same size.
a1 = b1;  // FAIL because the size of the array is part of the
//      template and thus the type, a1 and b1 are different types.
//      Thus this is a COMPILE time failure.
}

是的,它是一个非类型参数。您可以有几种类型的模板参数

  • 类型参数。
    • 类别
    • 模板(只有类和别名模板,没有函数或变量模板)
  • 非类型参数
    • 指示
    • 参考文献
    • 积分常数表达式

你手上的是最后一种。它是一个编译时间常量(所谓的常量表达式) ,类型为整数或枚举。在标准中查找之后,我不得不将类模板移动到类型部分-即使模板不是类型。但是,为了描述这些类型,它们被称为类型参数。您可以拥有指针(以及成员指针)和对具有外部链接的对象/函数的引用(可以从其他对象文件链接到这些对象/函数,并且这些对象/函数的地址在整个程序中是唯一的)。例子:

模板类型参数:

template<typename T>
struct Container {
T t;
};


// pass type "long" as argument.
Container<long> test;

模板整数参数:

template<unsigned int S>
struct Vector {
unsigned char bytes[S];
};


// pass 3 as argument.
Vector<3> test;

模板指针参数(传递指向函数的指针)

template<void (*F)()>
struct FunctionWrapper {
static void call_it() { F(); }
};


// pass address of function do_it as argument.
void do_it() { }
FunctionWrapper<&do_it> test;

模板引用参数(传递整数)

template<int &A>
struct SillyExample {
static void do_it() { A = 10; }
};


// pass flag as argument
int flag;
SillyExample<flag> test;

模板模板参数。

template<template<typename T> class AllocatePolicy>
struct Pool {
void allocate(size_t n) {
int *p = AllocatePolicy<int>::allocate(n);
}
};


// pass the template "allocator" as argument.
template<typename T>
struct allocator { static T * allocate(size_t n) { return 0; } };
Pool<allocator> test;

没有任何参数的模板是不可能的。但是没有任何明确参数的模板是可能的——它有默认参数:

template<unsigned int SIZE = 3>
struct Vector {
unsigned char buffer[SIZE];
};


Vector<> test;

在语法上,template<>被保留来标记一个显式的模板专门化,而不是一个没有参数的模板:

template<>
struct Vector<3> {
// alternative definition for SIZE == 3
};

模板类就像一个宏,只是没有那么邪恶。

把模板想象成一个宏。当您使用模板定义类(或函数)时,模板的参数将被替换为类(或函数)定义。

不同之处在于,参数具有“类型”,传递的值在编译期间被检查,就像函数的参数一样。有效的类型是常规的 C + + 类型,如 int 和 char。实例化模板类时,传递指定类型的值,并且在模板类定义的新副本中,无论参数名在原始定义中的哪个位置,该值都会被替换。就像宏一样。

您还可以使用“ class”或“ typename”类型作为参数(它们实际上是相同的)。使用这些类型之一的参数,可以传递类型名称而不是值。就像以前一样,在模板类定义中的任何地方,只要您创建一个新实例,就会变成您传递的任何类型。这是模板类最常见的用法; 所有了解 C + + 模板的人都知道如何做到这一点。

考虑一下这个模板类示例代码:

#include <cstdio>
template <int I>
class foo
{
void print()
{
printf("%i", I);
}
};


int main()
{
foo<26> f;
f.print();
return 0;
}

它在功能上与这个宏使用代码相同:

#include <cstdio>
#define MAKE_A_FOO(I) class foo_##I \
{ \
void print() \
{ \
printf("%i", I); \
} \
};


MAKE_A_FOO(26)


int main()
{
foo_26 f;
f.print();
return 0;
}

当然,模板版本的安全性和灵活性要高出十亿倍。