这个系列主要记录C++模板元编程的常用语法
文章目录
- 引言
- 语法
- 应用
- 函数模板
- 可变参数的打印
- 可变参数的最小/最大函数
- 类模板
- 参考文献
引言
在C++11之前,函数模板和类模板只支持含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含任意个(包括0个)模板参数,即可变参数模板。
语法
template<typename... Types>
其中 ...
可接纳的模板参数>=0。
如果不希望产生模板参数个数为0的变长参数模板,则可以采用以下定义:
template<typename Head, typename... Tail>
由于多了Head
类型,该模板必须有一个及以上的模板参数。
应用
函数模板
可变参数的打印
函数模板中一种常见的使用可变参数模板的场景是以递归的方式取出可用参数:
#include <iostream>
void print() {}
template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args) {
std::cout << firstArg << " " << sizeof...(args) << std::endl;
print(args...);
}
template <typename... Types>
void print(const Types&... args) {
std::cout << "print(...)" << std::endl;
}
int main(int argc, char* argv[]) {
print(3.0f, "hello world", 10);
return 0;
}
上面例子表示我们想要输出一个单精度浮点值+字符串+整型值:
- 上面的
void print() {}
代表模板递归的终止。 print(args...)
展开参数,向下模板递归。sizeof...(args)
得到参数的个数。
最终输出为
考虑如下情况,如果除了有上面的模板,我们还定义了一个完全泛化的模板:
template <typename... Types>
void print(const Types&... args) {
std::cout << "print(...)" << std::endl;
}
那么输出结果是怎么样的?
答案是还是输出上面的值,这是因为编译器对于偏泛化和偏特化都满足的情况,会选择偏特化的模板。
可变参数的最小/最大函数
有时我们想得到可变参数的最小/最大函数,可以如下实现:
#include <iostream>
template <typename T>
T m_min(T value) {
return value;
}
template <typename T, typename... Types>
T m_min(T value, Types... args) {
return std::min(value, m_min(args...));
}
int main(int argc, char *argv[]) {
std::cout << my_min(4, 3, 1, 2) << std::endl;
return 0;
}
类模板
可变参数模板也可以用于类模板中,比如STL中的tuple
:
#include <iostream>
template<typename... Values> class tuple;
template<> class tuple<> {};
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
: private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
public:
tuple() {}
tuple(Head v, Tail... vtail) : m_head(v), inherited(vtail...) {}
Head& head() { return m_head; }
inherited& tail() { return *this; }
protected:
Head m_head;
};
int main(int argc, char* argv[]) {
tuple<float, std::string, int> t(3.0f, "hello world", 10);
std::cout << t.head() << " " << t.tail().head() << " " << t.tail().tail().head() << std::endl;
return 0;
}
通过可变参数模板,实现递归继承,根基类为 template<> class<>{}
,父类成员在内存中位于子类成员之前。
这里的输出为
参考文献
【C++】C++11可变参数模板(函数模板、类模板)