将闭包作为参数传递给构造函数c ++

时间:2013-11-12 21:05:51

标签: c++ c++11 closures functor

在下面的代码中,我想摆脱使用各种类型的函数指针的奇怪构造函数,以及必须保存的参数列表(以及保存所有这些所需的所有成员变量) ),而是使用一个闭包来完成所有这些,让Event包含一个类似于Closure closure;的成员变量。有没有办法在C ++ 0x中使用闭包?

#include <iostream>
#include <list>
#include <functional>
#include <algorithm>

class Event
{
    std::function<double(double, double)> func1;
    bool func1Defined;
    double double1, double2;

    std::function<double(int, int, int)> func2;
    bool func2Defined;
    int int1, int2, int3;
public:
    void setFalse()
    {
        func1Defined = false;
        func2Defined = false;
    }
    Event(std::function<double(double, double)> func, double double1, double double2)
    {
        setFalse();
        func1 = func;
        func1Defined = true;
        this->double1 = double1;
        this->double2 = double2;
    }

    Event(std::function<double(int, int, int)> func, int int1, int int2, int int3)
    {
        setFalse();
        func2 = func;
        func2Defined = true;
        this->int1 = int1;
        this->int2 = int2;
        this->int3 = int3;
    }

    void run()
    {
        double ret = 0;
        if (func1Defined) ret = func1(double1, double2);
        else if (func2Defined) ret = func2(int1, int2, int3);
        /* do something with ret */
        std::cout << ret << "\n";
    }
};

double twoDoubleParam(double a, double b)
{
    return a + b;
}

double threeIntParam(int a, int b, int c)
{
    return (a + b) / c;
}

int main(int argc, char* argv[])
{
    std::list<Event> events;
    events.push_back(Event(*twoDoubleParam, 1.0, 3.5));
    events.push_back(Event(*threeIntParam, 2, 4, 2));
    std::for_each(events.begin(), events.end(), [&](Event event)
    {
        event.run();
    });

    int y;
    std::cin >> y;
    return 0;
}

不喜欢提升,但如果提升最好/只是简单的方法,我想知道如何。

4 个答案:

答案 0 :(得分:1)

看来你的Event应该只占一个std::function<double()>:独立于使用lambda,你想绑定参数来创建一个nullary函数(据我所知) ;如果每个调用都有实际参数,您显然会在std::function<Signature>中使用相应的签名。

假设您Eventfun类型的成员std::function<double()>

之类的构造函数
template <typename Fun>
Event::Event(Fun fun): fun(fun) {}

你可以,例如,使用

events.emplace_back([](){ return twoDoubleParam(1.0, 3.5); });
events.emplace_back(std::bind(&threeIntParam, 2, 4, 2));

这两种方法都可以使用std::bind()或lambda。我只是混合使用以获得其中一个。显然,如果你使用lambda并且参数不是常量而是值,那么你可以使用[=](){ ... }来按值捕获闭包值。

答案 1 :(得分:0)

使用std::bind执行此操作。见这里:http://en.cppreference.com/w/cpp/utility/functional/bind

它在VS2012 / 13,以及更新的GCC。如果您愿意,也可以将返回值直接分配给std::function<void()>

答案 2 :(得分:0)

看起来你想要std::bind

std::function<void()> func;

...

Event(std::function<double(double, double)> func, double d1, double d2) {
    func = std::bind(func, d1, d2);
}

// Repeat for the three ints

或者你可以让用户能够给出任何functor / args组合并为它们绑定它,比如std::thread的构造函数:

template<typename F, typename... Args>
Event(F&& f, Args&&... args) {
    func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
}

template<typename F, typename... Args>
Event(Args&&... args) {
    static_assert(sizeof...(Args) > 1, "Event() requires more than 1 argument");
    func = std::bind(std::forward<Args>(args)...);
}

答案 3 :(得分:0)

您可以使用std::bindstd::function

class Event {
    function<double()> func;
public:
    template <typename H, typename... Args>
    Event(H &&f, Args&&... args) 
          : func(bind(std::forward<H>(f), std::forward<Args>(args)...)) {}

    void run()
    {
        double ret = func();
        std::cout << ret << "\n";
    }
};

double twoDoubleParam(double a, double b) {
    return a + b;
}

double threeIntParam(int a, int b, int c) {
    return (a + b) / c;
}

int main(int argc, char* argv[]) {
    std::list<Event> events;
    events.push_back(Event(twoDoubleParam, 1.0, 3.5));
    events.push_back(Event(threeIntParam, 2, 4, 2));
    std::for_each(events.begin(), events.end(), [&](Event &event)
    {
        event.run();
    });
}

输出

4.5
3

Live code