C++11 可变参数模板

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11 可变参数模板相关的知识,希望对你有一定的参考价值。

在C++11之前, 有两个典型的受制于模板功能不强而导致代码重复难看的问题, 那就 function object 和 tuple。 拿 function objects 来说, 需要一个返回类型参数及N个参数类型参数。 但因为变长参数模板不受支持,导致不得不重复书写7、8个模板类,但最终也只能支持7、8个参数的 function object。C++11中最终为我们带来了强大的变长 参数模板功能,这些问题也随之迎刃而解了。 

可变参数模板(Variadic Template)故名思义,即可以接受任意数量参数的类/函数模板。 其声明方式为

template<typename... Args>
class VariadicTemplate;

当然non-type参数也是支持的比如 template<int... Args> class VariadicIntTemplate;

这里Args代表0-N个类型参数,也就是说VariadicTemplate<>也是有效的模板实例。

C++11 翻新了省略号(...)操作符来支持对这种模板参数的访问及使用。

类型展开

将所有模板参数展开在当前位置,用来调用其它模板、声明函数指针类型

技术分享
template<typename ...Args>
int foo() {
    int (*p)(Args...) = bar<Args...>;
    p(1, 0.5);
    return bar<Args...>(1, 0.5); 
}
技术分享

对于 foo<int, float> 实例,其 p 的类型为 int (*)(int, float) 而 return 语句将调用 bar<int, float>(1, 0.5)

此外还可以展开类型参数用来指定基类列表

template<typename... Args>
class foo : Args...{
};

foo<bar, barz> f; // 该类继承 bar, barz 两个基类

Parameter Packs / Initialization Lists

通过省略号操作符可以声明参数包,这些参数包可以在函数的参数位置展开。

template<typename ...Args>
void foo(Args... args) {
}

当使用 foo<int, float> 时,其有两参数,一个整数,一个float,因此调用方法为 foo<int, float>(1, 0.1f);

此外还可以将参数包展开到构造函数的初始化列表

技术分享
template<typename... Args>
class foo : Args...{
public:
    foo(Args...args):Args(args)...{
    }
};

foo<bar, barz> f(bar(), barz());
技术分享

sizeof... operator

要获取模板变长参数的实参长度,使用 sizeof... 运算符,它也可以被用于 Parameter Packs

技术分享
template<typename ... Args>
size_t foo() {
    return sizeof...(Args);
}
template<typename ... Args>
size_t fooz(Args ...args) {
    return sizeof...(args);
}
技术分享

以上就是变长参数的基本用法,但真正发挥作用,往往还要借助模板特化 (Template Specialization)

可变参数模板与模板特化

可变参数模板与普通模板一样,可以进行特化,从而实现一些有意义的模式

技术分享
template<typename ... Args>
void output(Args ... args) {
}
template<typename Arg0, typename ... Args>
void output(Arg0 arg0, Args ... args) {
    std::cout << arg0;
    output<Args...>(args...);
}
template<>
void output() {
}

/*------------------------------*/
typedef decltype(std::cout) cout_type;
auto endl = std::endl<cout_type::char_type, cout_type::traits_type>;
output(1, 0.3, (void*)nullptr, "string", c, endl);
技术分享

以上代码输出

10.30stringc

以上是关于C++11 可变参数模板的主要内容,如果未能解决你的问题,请参考以下文章

C++11 中的非类型可变参数函数模板

C++11 可变参数模板

第21课 可变参数模板_展开参数包

C++11新特性:9—— C++11在函数模板和类模板中使用可变参数

匹配任何类型参数的 C++ 可变参数模板模板参数

[C++11 模板的改进] --- 可变参数模板