我不明白这段代码(from Wikipedia)是如何工作的:
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 N>
?<>
?enum
erations for?谢谢!
答案 0 :(得分:23)
- 这个奇怪的模板需要
<int N>
?
在C ++中,模板参数可以是类型(前缀为class
或typename
)或整数(前缀为int
或unsigned int
)。我们在第二种情况下。
- 这第二个奇怪的是什么
template <>
?
template<> struct Factorial<0>
是Factorial类模板的完全特化,这意味着0
被认为是一个特殊的值,它对应于它自己的Factorial版本。
- 什么是枚举?
枚举是在元编程C ++中计算值的方法
- 使用此而不是正常的运行时因子计算有什么好处?
首先创建此代码的原因是创建一个概念证明,可以使用元编程来完成微积分。优点是生成的代码非常有效(调用Factorial<4>::value
等同于在代码中编写“24”。
- 你们多久使用一次这个?我一直在使用C ++,但之前从未使用过。我错过了C ++的大部分内容?
使用这种方法很少能实现这种功能,但现在越来越多地使用元编程。请参阅Boost meta-programming library以了解可以执行的操作。
答案 1 :(得分:6)
这个奇怪的模板是什么
<int N>
?
可以对类/类型,值和指针进行模板声明。您通常不会看到此表单,因为定义模板很少在模板参数中使用常量。
第二个奇怪的模板&lt;&gt;是什么?
考虑模板的最佳方法是执行与编译器类似的操作:将模板视为一个类,将模板参数替换为该类型的实际值。
即:对于:
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
Factorial<2>::value
相当于:
// generated by the compiler when Factorial<2>::value is encountered in code:
struct Factorial2 { enum { value = 2 * Factorial1::value }; };
struct Factorial1 { enum { value = 1 * Factorial0::value }; };
// not generated by compiler, as it was explicitly defined in the code you ask about:
template <> struct Factorial<0> { enum { value = 1 }; }; // defines Factorial<0>
什么是枚举?
它们在编译时使用const value
定义枚举,允许您编写客户端代码,如示例中所示。
使用它有什么好处 而不是正常的运行时因子 计算
优点是效率。由于在编译时扩展了值计算,因此Factorial<10>::value
的运行时成本与Factorial&lt; 1&gt; :: value相同。在编译的代码中,它们都是常量。如果要在性能关键代码中计算阶乘,并且在编译时知道它是哪个值,则应该执行此操作,或者离线计算并在代码中使用预先计算的值定义常量。
你们多久使用一次这个?
“this”是指你对常量的递归计算吗?如果是这样,不经常。
“this”是模板中常量的定义吗?经常:)
“this”是特定类型模板的特殊化吗?非常非常非常。我知道std :: vector在一些STL实现中有一个完全独立的实现(一个std::vector<bool>
,其中8个元素不需要超过1个字节来存储值。)
我已经使用C ++一段时间了, 但从来没有用过这个。多大了 我错过了C ++的一部分?
不一定很重要。如果你使用boost,你使用的代码很可能是用这样的东西实现的。
答案 2 :(得分:4)
我发现this answer Johannes Schaub - litb对另一个问题很有帮助。
[我在这里复制粘贴答案,假设约翰内斯对它没问题。如果他不喜欢,我会删除粘贴]
是的,它是一个非类型参数。您可以使用多种模板参数
你拥有的是最后一种。它是一个编译时常量(所谓的常量表达式),是整数或枚举类型。在标准中查找之后,我不得不将类模板移动到类型部分 - 即使模板不是类型。但它们被称为类型参数,目的是为了描述这些类型。您可以拥有指针(以及成员指针)和对具有外部链接的对象/函数的引用(可以链接到其他目标文件并且其地址在整个程序中是唯一的)。例子:
模板类型参数:
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
};
答案 3 :(得分:3)
使用此而不是正常的运行时因子计算有什么好处?
速度更快 - 理论上编译器会在编译时扩展模板集,使Factorial<n>::value
只是一个常量。在一些极少数情况下,这可能会产生很大的不同。
它的缺点是它必须在编译时计算,所以如果在运行时确定n
,则不能使用该方法。
你们多久使用一次这个?我一直在使用C ++一段时间了, 但从来没有用过这个。我错过了C ++的大部分内容?
这样的情况,根本不常见。模板元编程可能非常强大,但此示例有用且对性能而言非常重要的案例数量很少。
但它在C ++中是一种有用的技术,因为它允许语言执行许多强大的技巧,否则这些技巧将无法实现。我敢说,利用其他人为你做过的模板元编程更为常见 - 例如。 Boost使用它非常重,因此可以做一些非常聪明的事情。它功能强大,但如果做得不好也会混淆代码。
答案 4 :(得分:2)
它是由编译器执行的递归,其中
template <>
struct Factorial<0>
{
}
是递归的退出点。
首先Factorial<4>
已解决。 {4}没有Factorial
的特化,因此使用了第一个定义Factorial<>
。
然后使用Factorial<3>::value
计算其值,其中重复上一步。
这将继续,直到N == 1,然后对于N-1,专门化Factorial<0>
开始起作用,其中值设置为1.递归在此处停止,编译器可以向上并且计算Factorial<N>
的剩余值。