如何在所有可变参数模板上调用函数? [英] How to call a function on all variadic template args?

查看:93
本文介绍了如何在所有可变参数模板上调用函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要做

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆