可变参数模板是一个模板,它可以接受任意数量的任意类型的模板参数。自 C 语言诞生以来,这两个函数都可以是可变参数(例如 printf 函数),然后是宏,现在是模板。
你可以这样声明:
template<typename... Arguments> class Variadic;
然后用任意数量的参数对其进行专门化,包括零:
Variadic<double> instance;
Variadic<double, std::string> instance;
Variadic<> instance;
然后你可以使用参数列表,称为参数包,如下所示:
template<typename... Arguments> void SampleFunction(Arguments... parameters);
就像可变参数函数一样,参数包前面可以有具体参数:
template<typename First, typename... Rest> class BunchOfValues;
在 STL 中有一个经典的可变参数模板示例:std::tuple。一些编译器不完全支持或根本不支持此功能,在他们的情况下,元组是通过元编程和宏定义实现的。
C++ 中没有直接的方法从列表中选择特定参数,就像使用可变参数函数一样。可以使用递归在一个方向上遍历它们:
template<typename T> foo(T first)
{
// do something;
}
template<typename T, typename U, typename ... Args> foo(T first, U second, Args... Rest)
{
// do something with T
foo(second, Rest...);
}
通常迭代将依赖于函数重载,或者 - 如果函数一次只能选择一个参数 - 使用哑扩展标记:
template<typename... Args> inline void pass(Args&&...) {}
可以这样使用:
template<typename... Args> inline void expand(Args&&... args) {
pass( some_function(args)... );
}
expand(42, "answer", true);
这将扩展为:
pass( some_function(arg1), some_function(arg2), some_function(arg3) etc... );
使用这个“pass”函数是必要的,因为参数包的扩展是通过逗号分隔函数调用参数来进行的,这不等同于逗号运算符。 some_function(args)...; 永远不会工作。此外,上述解决方案仅在 some_function 的返回类型不为 void 时才有效。此外, some_function 调用将以未指定的顺序执行,因为函数参数的评估顺序未定义。为了避免未指定的顺序,可以使用大括号括起来的初始化列表,这保证了严格的从左到右的评估顺序。为避免需要非 void 返回类型,逗号运算符可用于在每个扩展元素中始终产生 1。
struct pass {
template<typename ...T> pass(T...) {}
};
pass{(some_function(args), 1)...};
参数包中的参数个数可以由sizeof...(args)表达式确定。
在创建使用调用 name 的初始化程序时,只有在编写代码时定义 name 才有可能。预处理器中有stingizer operator#可以使用,例如
#define printstring( x ) printf(#x "\n")
printstring( This a dumb idea );
将生成代码(假设 C++ 自动加入字符串文字):
printf("This a dumb idea \n")
你可以这样声明:
template<typename T> class moniker
{
public:
moniker(const char* tname);
}
#define declare_moniker(type, name) moniker<type> name(#type)
可变参数宏定义和可变参数模板如何交互?我不知道。我手头的编译器失败了,但它不是 C++11。有兴趣可以试试。
可能支持 typeid 运算符,具体取决于编译器设置。
const std::type_info& ti1 = typeid(A);
std::type_info 获得了方法名(),但它返回的字符串取决于实现:http://en.cppreference.com/w/cpp/types/type_info/name