2

在下面的代码中,我想摆脱采用各种类型函数指针的奇怪构造函数,以及必须保存的参数列表(以及保存所有这些所需的所有成员变量),并且而是使用闭包来完成所有这些工作,给 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

4 回答 4

2

看来你Event应该首先持有 a std::function<double()>:独立于是否使用 lambda,你想绑定参数以创建一个空函数(据我所知;如果每个调用都有实际参数,你会显然在std::function<Signature>.

假设你Event有一个fun类型的成员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 并且参数不是常量而是值,您将使用[=](){ ... }按值捕获闭包值。

于 2013-11-12T21:16:18.367 回答
1

您可以使用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

实时代码

于 2013-11-12T21:14:20.377 回答
0

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

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

于 2013-11-12T21:09:25.453 回答
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

或者,您可以让用户能够提供任何仿函数/参数组合并为它们绑定它,例如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)...);
}
于 2013-11-12T21:09:32.517 回答