矢量std ::功能与不同的签名

ksl*_*ksl 14 c++ stdvector c++11 std-function

我有许多具有不同签名的回调函数.理想情况下,我想将它们放在一个向量中,并根据某些条件调用适当的一个.

例如

void func1(const std::string& value);

void func2(const std::string& value, int min, int max);

const std::vector<std::function<void(std::string)>> functions
{
    func1,
    func2,
};
Run Code Online (Sandbox Code Playgroud)

我意识到上述情况是不可能的,但我想知道是否有任何我应该考虑的替代方案.我还没有找到任何东西,我已经尝试过,std::bind但没有成功实现我想要的东西.

这样的事情可能吗?

Jon*_*ely 21

func2在将它放入错误类型的向量之后,您没有说过您希望能够做什么.

std::bind如果您提前知道参数,则可以轻松地将其放入向量中:

const std::vector<std::function<void(std::string)>> functions
{
    func1,
    std::bind(func2, std::placeholders::_1, 5, 6)
};
Run Code Online (Sandbox Code Playgroud)

现在functions[1]("foo")将调用func2("foo", 5, 6),并会把56func2每一次.

使用lambda代替的是同样的事情 std::bind

const std::vector<std::function<void(std::string)>> functions
{
    func1,
    [=](const std::string& s){ func2(s, func2_arg1, func2_arg2); }
};
Run Code Online (Sandbox Code Playgroud)

如果您还不知道参数,可以绑定对某些变量的引用:

int func2_arg1 = 5;
int func2_arg2 = 6;
const std::vector<std::function<void(std::string)>> functions
{
    func1,
    std::bind(func2, std::placeholders::_1, std::ref(func2_arg1), std::ref(func2_arg2))
};
Run Code Online (Sandbox Code Playgroud)

现在functions[1]("foo")将调用func2("foo", func2_arg1, func2_arg2),您可以为整数分配新值以传递不同的参数func2.

并使用lambda函数代替 std::bind

const std::vector<std::function<void(std::string)>> functions
{
    func1,
    [&](const std::string& s){ func2(s, func2_arg1, func2_arg2); }
};
Run Code Online (Sandbox Code Playgroud)

这非常难看,因为int只要引用它们的可调用对象(闭包或绑定表达式)存在,就需要保持变量.


Sva*_*zen 6

你想要什么是可能的polymorphism.我们的想法是创建一个具有特定签名的类,在运行时将调用不同的方法.例如:

#include <iostream>
#include <functional>
#include <memory>
#include <vector>

void foo(int) {
    std::cout << "I'm foo!\n";
}

int bar(char, double) {
    std::cout << "I'm bar!\n";
}

class MyFunction {
    public:
        virtual ~MyFunction(){}

        virtual void operator()() = 0;
};

class MyFunctionA : public MyFunction {
    public:
        virtual void operator()() {
            foo(4);
        }
};

class MyFunctionB : public MyFunction {
    public:
        MyFunctionB(std::function<int(char,double)> f, char arg1, double arg2) : fun_(f), arg1_(arg1), arg2_(arg2) {} 

        virtual void operator()() {
            fun_(arg1_, arg2_);
        }
    private:
        std::function<int(char,double)> fun_;
        char arg1_;
        double arg2_;
};

int main() {
    using MyFunPtr = std::unique_ptr<MyFunction>;
    std::vector<MyFunPtr> v;

    v.emplace_back(new MyFunctionA());
    v.emplace_back(new MyFunctionB(bar, 'c', 3.4));

    for ( auto&& myfun : v ) {
        (*myfun)();
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您可以根据需要使派生类变得复杂,但由于最终它们都具有相同的接口,因此您可以调用所有这些类.