2

受我上一个问题的启发:制作可变参数函数,该函数采用任意函子并返回输入函子的每个返回值的元组

现在,我想创建一个只执行每个可能返回 void 的函数对象的类。据我所知,我可以制作类似的东西,

class A
{
public:
    template <class Func>
    void operator()(Func func)
    {
        func();
    }

    template <class First, class... Funcs>
    void operator()(First first, Funcs... funcs)
    {
        first();
        operator()(funcs...);
    }
};

这段代码完成了这项工作。但是,我想上面链接中Nawaz的代码必须有更聪明的方法。mfontanini

我在下面尝试模仿他们的代码。

class A
{
public:
    template <class... Func>
    void operator()(Func func...)
    {
        func()...;
    }
};

但是,gcc 4.7.2 无法编译。我在这里失踪了吗?

4

2 回答 2

4

要扩展 Nawaz 的答案,您需要特定的上下文来执行包扩展 - 它不能在任何地方完成。其中一个上下文是函数参数,另一个是任何类型的初始化。

Nawaz 给出的sink函数是一个很好的起点,但它有一个严重的缺陷——你没有保证函子执行的顺序。如果您希望您的用户能够依赖他们传递给您的顺序,您需要一个确保从左到右评估的上下文。数组初始化和列表初始化都适合这里。

使用数组初始化:

template <class... Func>
void operator()(Func func...)
{
    int ignored[] = { (func(),0)... };
    (void)ignored; // silence unused variable warnings
}

使用列表初始化:

struct swallow{
  template<class... Ignored>
  swallow(Ignored&&...)
};

template <class... Func>
void operator()(Func func...)
{
    swallow{ (func(),0)... }; // create a temporary 'swallow' from all arguments
}

(func(), 0)部分只是执行func,丢弃返回值(如果有),然后计算为0

通常,如果您想对任何仿函数执行此操作,而不管返回类型如何,并且只是丢弃结果,您会将其写为(void(func()), 0).... 如果有的话,该void(...)部分会吞下来自 的任何返回值func()。这是必需的,因为允许用户重载operator,,并且可能决定为他自己的类型和int(字面量的类型0)这样做,这会破坏您的努力。但是,您不能operator,void任何方面超载。

于 2013-02-25T07:50:09.847 回答
3

你可以这样做:

template <class... Func>
void operator()(Func ... func) //corrected the syntax here
{
    sink( (func(),0)... );
}

其中sink定义为:

template<typename ...T> void sink(T...) {}

的目的sink是吃掉表达式的值,而不管返回的是(func(),0)什么。即使返回类型为.0func()func()void

请注意,在上面的演示中,前两个函数返回了一些东西,但第三个返回了void

如果您希望从左到右调用函数,则可以使用列表初始化语法:

 int sink[]{func(),0)... };

但它不必要地创建了一个变量。所以我会定义sink为结构:

struct sink
{
     template<typename ...T> 
     sink(T...) {}  //templated constructor!
};

有了这个,你可以这样做:

sink { (func(),0)... }; //note the curly-braces now!

更新的演示:

希望有帮助。

于 2013-02-25T07:42:04.357 回答