使用非类型模板参数而不是常规参数的原因
Reason for using non-type template parameter instead of regular parameter?
在c++中,您可以使用如下的非类型模板参数创建模板:
template< int I >
void add( int& value )
{
value += I;
}
int main( int argc, char** argv )
{
int i = 10;
add< 5 >( i );
std::cout << i << std::endl;
}
输出"15"到计数。这有什么用?是否有理由使用非类型模板形参,而不是像
这样更常规的形参:void add( int& value, int amount )
{
value += amount;
}
对不起,如果这已经问过了(我看了,但找不到任何东西)。
非类型模板参数有很多应用;以下是一些:
可以使用非类型参数来实现表示固定大小的数组或矩阵的泛型类型。例如,您可以在维度上参数化Matrix
类型,因此您可以创建Matrix<4, 3>
或Matrix<2, 2>
。如果正确地为这些类型定义了重载操作符,就可以防止因添加或相乘维度不正确的矩阵而导致的意外错误,并且可以使函数显式地传达它们接受的矩阵的预期维度。这可以通过在编译时检测违规来防止大量运行时错误的发生。
可以使用非类型参数通过模板元编程实现编译时函数求值。例如,下面是一个在编译时计算阶乘的简单模板:
template <unsigned n> struct Factorial {
enum {
result = n * Factorial<n - 1>::result
};
};
template <> struct Factorial<0> {
enum {
result = 1
};
};
这允许您编写像Factorial<10>::result
这样的代码来在编译时获得10!的值。这可以防止在运行时执行额外的代码。
此外,您可以使用非类型参数来实现编译时维度分析,这允许您定义千克、米、秒等类型,这样编译器就可以确保您不会意外地在表示米的地方使用千克等。
希望这对你有帮助!
在这种情况下,您可能是对的,但在某些情况下,您需要在编译时了解这些信息:
但是这个呢?
template <std::size_t N>
std::array<int, N> get_array() { ... }
std::array
需要在编译时知道它的大小(因为它是在堆栈上分配的)。
你不能这样做:
std::array<int>(5);
这是编译时多态和运行时多态之间的典型选择。
从你的问题的措辞来看,你似乎在"普通"模板参数中没有看到任何异常,而认为非类型参数是奇怪的和/或多余的。实际上,同样的问题也可以应用于模板类型参数(您称之为"普通"参数)。相同的功能通常可以通过带有虚函数的多态类(运行时多态性)或通过模板类型参数(编译时多态性)来实现。也有人会问,为什么我们需要模板类型参数,因为几乎所有东西都可以使用多态类实现。在非类型参数的情况下,您可能希望有一天有这样的东西template <int N> void foo(char (&array)[N]) {
...
}
在这种特殊情况下,实际上没有任何优势。但是使用这样的模板参数,你可以做很多你不能做的事情,比如有效地将变量绑定到函数(如boost::bind
),在函数或类中指定编译时数组的大小(std::array
就是一个现成的例子),等等。
例如,对于该函数,您可以编写如下函数
template<typename T>
void apply(T f) {
f(somenum);
}
那么你可以给apply
传递一个函数:
apply(&add<23>);
这是一个极其简单的例子,但它演示了原理。更高级的应用包括将函数应用于集合中的每个值,在编译时计算函数的阶乘等。
有很多原因,比如做模板元编程(检查Boost.MPL)。但是没有必要走那么远,c++ 11的std::tuple
有一个访问器std::get<i>
,需要在编译时索引,因为结果依赖于索引。
我能想到的值参数最常用的用法是std::get<N>
,它检索std::tuple<Args...>
的第n个元素。第二常用的是std::integral_constant
及其主要衍生物std::true_type
和std::false_type
,它们在任何类型的性状类中都是普遍存在的。事实上,类型特征绝对充满了值模板参数。特别是,SFINAE技术利用签名<typename T, T>
的模板来检查类成员的存在。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 将矢量设置为常规参数
- 如何使用模板生成常规参数列表并将其传递给运行时函数?
- 取决于参数的数量,将其返回结构对象,并将其分配给常规结构的对象
- 常规/动态类型作为参数C/C++
- 如何使用常规函数指针作为模板参数
- 为什么std::get使用模板参数而不是常规参数
- 使用非类型模板参数而不是常规参数的原因