13

如何从成员函数创建 std::function 而无需键入 std::placeholders::_1、std::placeholders::_2 等 - 我想“占位”所有参数,只保存对象本身。

struct Foo{
  int bar(int,float,bool) {return 0;}
};
int baz(int,float,bool) {return 0;}
int main() {
  Foo object;
  std::function<int(int,float,bool)> fun1 = baz; // OK
  std::function<int(int,float,bool)> fun2 = std::bind(&Foo::bar, object); // WRONG, needs placeholders
}

我不想在这个阶段提供参数,我只想将函数 + 对象存储在某个地方。例如,我希望 std::vector 同时具有全局函数和成员函数。使用 FastDelegate ( ) 很容易做到fastdelegate::MakeDelegate(object, &Class::function)

我不想使用 lambda,因为它也需要我重新输入参数。我只想要旧的 FastDelegate 行为。

4

3 回答 3

16

您可以使用函数模板来推断所有成员函数参数类型,如下所示:

template<typename Obj, typename Result, typename ...Args>
auto make_delegate(const Obj &x, Result (Obj::*fun)(Args...)) -> // ...

并将返回特殊的委托对象,该对象将包含您的对象(或指向它的指针),并将所有传递的参数转发给底层对象的成员函数:

template<typename Obj, typename Result, typename ...Args>
struct Delegate
{
    Obj x;
    Result (Obj::*f)(Args...);

    template<typename ...Ts>
    Result operator()(Ts&&... args)
    {
        return (x.*f)(forward<Ts>(args)...);
    }
};

您将获得以下使用语法:

function<int(int,float,bool)> fun = make_delegate(object, &Foo::bar);

这是完整的示例:

#include <functional>
#include <iostream>
#include <utility>

using namespace std;

struct Foo
{
    int bar(int x, float y, bool z)
    {
        cout << "bar: " << x << " " << y << " " << z << endl;
        return 0;
    }
};

int baz(int x, float y, bool z)
{
    cout << "baz: " << x << " " << y << " " << z << endl;
    return 0;
}

template<typename Obj, typename Result, typename ...Args>
struct Delegate
{
    Obj x;
    Result (Obj::*f)(Args...);

    template<typename ...Ts>
    Result operator()(Ts&&... args)
    {
        return (x.*f)(forward<Ts>(args)...);
    }
};

template<typename Obj, typename Result, typename ...Args>
auto make_delegate(const Obj &x, Result (Obj::*fun)(Args...))
    -> Delegate<Obj, Result, Args...>
{
    Delegate<Obj, Result, Args...> result{x, fun};
    return result;
}

int main()
{
    Foo object;
    function<int(int,float,bool)> fun[] =
    {
        baz,
        make_delegate(object, &Foo::bar) // <---- usage
    };
    for(auto &x : fun)
        x(1, 1.0, 1);
}

输出是:

baz: 1 1 1
bar: 1 1 1

Coliru 上的现场演示

于 2013-10-30T19:42:08.650 回答
4

如果您不想使用占位符,那么std::bind不适合您:

使用 lambda:

Foo object;

std::function<int(int,float,bool)> fun = [&object](int a, float b, bool c) {
        return object.bar(a,b,c);
};

object如果您愿意,您可以按价值捕获。也许您意识到这并不比使用占位符更好,因为您无论如何都在输入参数 - 实际上在这种情况下您输入的更多

于 2013-10-30T19:22:55.453 回答
1

您可以使用 C++14 中的可变参数泛型 lambda 轻松做到这一点:

template<typename F, typename C>
auto smart_bind(F f, C* c)
{
  return [c, f](auto&&... args) { return (c->*f)(std::forward<decltype(args)>(args)...); };
}

// In your code:
std::function<int(int,float,bool)> fun2 = smart_bind(&Foo::bar, &object);

现场演示:https ://ideone.com/deR4fy

于 2018-03-19T14:40:13.820 回答