如何在所有可变参数模板上调用函数? [英] How to call a function on all variadic template args?
问题描述
我想要做
template<typename... ArgTypes> void print(ArgTypes... Args)
{
print(Args)...;
}
并且等价于这个庞大的递归链:
And have it be equivalent to this quite bulky recursive chain:
template<typename T, typename... ArgTypes> void print(const T& t, ArgTypes... Args)
{
print(t);
print(Args...);
}
,然后为每种类型显式单参数特殊化。
followed by explicit single-parameter specializations for every type I'd like to print.
递归实现的问题是生成了大量的冗余代码,因为每个递归步骤都会产生一个新的函数 N-1
参数,而我想要的代码只会生成一个 N
-arg print
函数,并且最多有 N
特殊打印
函数。 b $ b
The "problem" with the recursive implementation is that a lot of redundant code is generated, because each recursive step results in a new function of N-1
arguments, whereas the code I'd like to have would only generate code for a single N
-arg print
function, and have at most N
specialized print
functions.
推荐答案
这里的典型方法是使用一个哑的列表初始化器,并在里面进行扩展:
The typical approach here is to use a dumb list-initializer and do the expansion inside it:
{ print(Args)... }
Order of evaluation is guaranteed left-to-right in curly initialisers.
但打印
返回 void
,所以我们需要解决这个问题。让我们把它变成一个整数。
But print
returns void
so we need to work around that. Let's make it an int then.
{ (print(Args), 0)... }
这不会直接作为语句工作。我们需要给它一个类型。
This won't work as a statement directly, though. We need to give it a type.
using expand_type = int[];
expand_type{ (print(Args), 0)... };
只要总是有一个元素 Args
pack。零大小的数组是无效的,但我们可以通过使它总是有至少一个元素。
This works as long as there is always one element in the Args
pack. Zero-sized arrays are not valid, but we can work around that by making it always have at least one element.
expand_type{ 0, (print(Args), 0)... };
我们可以使用宏来重用这个模式。
We can make this pattern reusable with a macro.
namespace so {
using expand_type = int[];
}
#define SO_EXPAND_SIDE_EFFECTS(PATTERN) ::so::expand_type{ 0, ((PATTERN), 0)... }
// usage
SO_EXPAND_SIDE_EFFECTS(print(Args));
但是,使这个可重用的需要更多的注意一些细节。我们不想在这里使用重载的逗号运算符。逗号不能重载的参数 void
之一,所以让我们利用这个。
However, making this reusable requires a bit more attention to some details. We don't want overloaded comma operators to be used here. Comma cannot be overloaded with one of the arguments void
, so let's take advantage of that.
#define SO_EXPAND_SIDE_EFFECTS(PATTERN) \
::so::expand_type{ 0, ((PATTERN), void(), 0)... }
如果你是 paranoid 害怕编译器分配大数组的零零,你可以使用一些其他类型
If you are paranoid afraid of the compiler allocating large arrays of zeros for naught, you can use some other type that can be list-initialised like that but stores nothing.
namespace so {
struct expand_type {
template <typename... T>
expand_type(T&&...) {}
};
}
这篇关于如何在所有可变参数模板上调用函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!