web-dev-qa-db-fra.com

Comment lier directement une fonction membre à une fonction std :: dans Visual Studio 11?

Je peux facilement lier des fonctions membres à un std::function en les enveloppant avec une expression lambda avec une clause de capture.

class Class
{
    Class()
    {
        Register([=](int n){ Function(n); });
    }

    void Register(std::function<void(int)> Callback)
    {

    }

    void Function(int Number)
    {

    }
};

Mais je veux les lier directement, quelque chose comme ce qui suit.

// ...
Register(&Class::Function);
// ...

Je pense que selon la norme C++ 11, cela devrait être pris en charge. Cependant, dans Visual Studio 11, j'obtiens ces erreurs de compilation.

erreur C2440: "nouvelle ligne": impossible de convertir de "int" en "classe *"

erreur C2647: '. *': ne peut pas déréférencer un 'void (__thiscall Class :: *) (int)' sur un 'int'

22
danijar

Je pense que selon la norme C++ 11, cela devrait être pris en charge

Pas vraiment, car une fonction membre non statique a un premier paramètre implicite de type (qualifié cv) YourType*, Donc dans ce cas, il ne correspond pas à void(int). D'où la nécessité de std::bind :

Register(std::bind(&Class::Function, PointerToSomeInstanceOfClass, _1));

Par exemple

Class c;
using namespace std::placeholders; // for _1, _2 etc.
c.Register(std::bind(&Class::Function, &c, _1));

Edit Vous mentionnez que cela doit être appelé avec la même instance Class. Dans ce cas, vous pouvez utiliser une simple fonction non membre:

void foo(int n)
{
  theClassInstance.Function(n);
}

puis

Class c;
c.Register(foo);
38
juanchopanza

Selon Stephan T. Lavavej - "Évitez d'utiliser bind (), ..., utilisez lambdas". https://www.youtube.com/watch?v=zt7ThwVfap0&t=32m20s

Dans ce cas:

Class()
{
    Register([this](int n){ Function(n); });
}
33
Andy

Vous pouvez utiliser std::bind :

using namespace std::placeholders;  // For _1 in the bind call

// ...

Register(std::bind(&Class::Function, this, _1));
9

En C++ 17, vous pouvez utiliser:

Register([=](auto && ...args){ return Function(args...); });

ce qui est particulièrement agréable si la liste des arguments est plus longue. Bien entendu, la liste des arguments de la fonction membre doit alors être compatible avec celles de std::function.

3
peterchen

Avec std::function et std::bind, vous pouvez traiter la même fonction de membre de classe de la même manière.

#include <iostream>
#include <functional>
#include <vector>
using namespace std;
using namespace std::placeholders;

class Foo
{
public:
    void foo(const string &msg)
    {
        cout << msg << '\n';
    }
};

class Bar
{
public:
    void bar(const string &msg, const string &suffix)
    {
        cout << msg << suffix << '\n';
    }
};

int main(int argc, char **argv)
{
    Foo foo;
    Bar bar;

    vector<function<void (const string &msg)>> collection;
    collection.Push_back(bind(&Foo::foo, &foo, _1));
    collection.Push_back(bind(&Bar::bar, &bar, _1, "bar"));

    for (auto f : collection) {
        f("foo");
    }

    return 0;
}
1
Richard