Передача функции-члена со всеми аргументами в std:: function

Как я могу создать std:: функцию из функции-члена без необходимости ввода 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)).

Я не хочу использовать лямбда, так как это потребует от меня повторных аргументов. Мне просто нужно старое поведение FastDelegate.

Ответ 1

Вы можете использовать шаблон функции, который выведет все типы параметров функции-члена, например:

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

Live Demo on Coliru

Ответ 2

Если вы не хотите использовать заполнители, то std::bind не для вас:

Используйте лямбда:

Foo object;

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

Вы можете записать object по значению, если хотите. Возможно, вы понимаете, что это не лучше, чем использование заполнителей, поскольку вы все равно печатаете параметры — на самом деле вы вводите больше в этом случае!