2013-06-16 5 views
6

Я могу легко связать функции-члены с std::function, обернув их выражением лямбда с предложением захвата.Как напрямую связать функцию-член с функцией std :: в Visual Studio 11?

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

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

    } 

    void Function(int Number) 
    { 

    } 
}; 

Но я хочу связать их напрямую, что-то вроде следующего.

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

Я думаю, что согласно стандарту C++ 11, это должно поддерживаться. Однако в Visual Studio 11 я получаю эти ошибки компилятора.

ошибка C2440: 'перевод строки': не удается преобразовать из 'межд' до 'Класс *'

ошибка C2647: '*': не может разыменовывать Пустота (__thiscall Class :: *) (интермедиат)»на 'Int'

ответ

17

Я думаю, что в соответствии со стандартом C++ 11, то это должно быть поддержано

Не совсем, потому что не статическая функция-член имеет implic это первый параметр типа (cv-qualified) YourType*, поэтому в этом случае он не соответствует void(int). Отсюда вытекает необходимость std::bind:

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

Например

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

Редактировать Вы упоминаете, что это будет называться с той же Class инстанции. В этом случае, вы можете использовать простую функцию, не являющуюся членом:

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

затем

Class c; 
c.Register(foo); 
+0

Работает, но может быть упрощен синтаксис при ограничении, что все ссылки класса одинаковы? – danijar

+0

@ danijar, что вы подразумеваете под всеми ссылками на класс? Вам нужно передать указатель на экземпляр класса. Который вы проходите, зависит от вас. – juanchopanza

+0

Справа. И этот экземпляр всегда будет таким же. Теперь я хотел бы укоротить «bind (& Class :: Function, this, _1)» с учетом этой информации. Таким образом, «привязка» дословно устарела. Есть ли технический способ избавиться от него или выполнить привязку внутри функции после прохождения? – danijar

4

Вы можете использовать std::bind:

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

// ... 

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

Скажите, я хочу установить этот указатель функции в качестве аргумента по умолчанию для функции. Это возможно? Я не могу использовать вызовы типа 'bind', а? У меня нет указателя 'this' для поиска в списке параметров. – danijar

+1

@ danijar Это невозможно, но его можно обойти, имея перегруженный вариант 'Register' без аргументов, которые привязываются к вашей функции по умолчанию. –

+0

Хорошая идея, спасибо. – danijar

0

С std::function и std::bind, вы можете обращаться с различными функция члена класса такая же.

#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; 
} 
11

По словам Стефана Т. Лававей - «Избегайте использования bind(), ..., используйте lambdas». https://www.youtube.com/watch?v=zt7ThwVfap0&t=32m20s

В этом случае:

Class() 
{ 
    Register([this](int n){ Function(n); }); 
} 
+0

спасибо за указание на это и ссылку на соответствующую часть видео! –

 Смежные вопросы

  • Нет связанных вопросов^_^