2015-12-21 2 views
0

Я пытался работать на код ниже, но программа аварий:Каков наилучший способ передать функцию обратного вызова на std :: map?

#include <iostream> 
#include <string> 
#include <map> 

using namespace std; 

typedef void (*callBackMethod)(string); 
class CTest 
{ 
private: 
    map<string, callBackMethod> mapMethod; 

    void testMethod(string msg) 
    { 
     cout << msg << endl; 
    } 
public: 
    CTest() 
    { 
     addFunction("AA", (callBackMethod) &CTest::testMethod); 
    } 
    void addFunction(string funName, callBackMethod methodName) 
    { 
     mapMethod[funName] = methodName; 
    } 
    callBackMethod getMethod(string funName) 
    { 
     auto fun = mapMethod.find(funName); 
     if(fun == mapMethod.end()) { return nullptr; } 
     return fun->second; 
    } 
    void runFunction(string funName) 
    { 
     getMethod(funName)("test"); 
    } 

}; 

int main() 
{ 
    CTest test; 
    test.runFunction("AA"); 

    return 0; 
} 

У меня есть требование, когда мне нужно передать частные методы на карте. Программа компилируется с предупреждением:

converting from 'void (CTest::*)(std::__cxx11::string) {aka void (CTest::*)(std::__cxx11::basic_string<char>)}' to 'callBackMethod {aka void (*)(std::__cxx11::basic_string<char>)}' 

И когда я выполняю это, он падает.

Когда я перемещаю метод обратного вызова вне класса, он работает. Мое требование состоит в том, чтобы сделать этот поток программы (скрыть методы из внешнего вызова, которые необходимо добавить на карту).

Ждем ваших комментариев.

+1

Почему, по вашему мнению, отличная функция-указатель на функцию - это хорошая идея ?! –

+0

@ T.C. Тогда что вы предлагаете? Пожалуйста, измените код, если хотите. – programmer

+0

Возможный дубликат [как передать функцию нестационарного члена в качестве обратного вызова?] (Http://stackoverflow.com/questions/2097738/how-to-pass-a-non-static-member-function-as- a-callback) –

ответ

0

Если вам нужно чтобы указать на функции CTest и бесплатные функции, вы можете использовать std::function<void(std::string)>.

#include <iostream> 
#include <string> 
#include <map> 
#include <functional> 

using namespace std; 

using callBackFunction = std::function<void(string)>; 

void testFunction(string msg) 
{ 
    cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl; 
} 

class CTest 
{ 
private: 
    map<string, callBackFunction> mapMethod; 

    void testMethod(string msg) 
    { 
     cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl; 
    } 
public: 
    CTest() 
    { 
     addFreeFunction("AA", testFunction); 
     addMemberFunction("BB", &CTest::testMethod); 
    } 
    void addMemberFunction(string funName, void(CTest::*methodName)(string)) 
    { 
     using std::placeholders::_1; 
     mapMethod[funName] = std::bind(methodName, this, _1); 
    } 
    void addFreeFunction(string funName, void(*methodName)(string)) 
    { 
     mapMethod[funName] = methodName; 
    } 
    callBackFunction getMethod(string funName) 
    { 
     auto fun = mapMethod.find(funName); 
     if(fun == mapMethod.end()) { return nullptr; } 
     return fun->second; 
    } 
    void runFunction(string funName) 
    { 
     getMethod(funName)("test"); 
    } 

}; 

int main() 
{ 
    CTest test; 
    test.runFunction("AA"); 
    test.runFunction("BB"); 

    return 0; 
} 

Обратите внимание, что CTest должны вставлять элементы в карты по-разному в зависимости от того, какой тип функции вы передаете, поскольку для функций-членов необходимо предоставить объект, для которого он должен быть вызван, this в этом пример. Это достигается с помощью std::bind.

+0

спасибо. Ваш код работал. Но теперь подпись метода обратного вызова скрыта. Мне также нужно передать методы обратного вызова из основного. Например: void tst2 (строка s) {cout << "New" << s;} .... и внутри main() {.... test.addFunction ("BB", &tst2); ...} завершается с ошибкой ошибка компиляции.Есть ли лучший способ справиться с этим случаем. Большое спасибо. – programmer

+0

Итак, вам нужно использовать как функции-члены, так и функции, не являющиеся членами? –

+0

есть. Мне нужно использовать функции-члены и не-члены. – programmer

0

Поскольку вы хотите использовать переменные-члены необходимо указать подпись по-разному в вашем typedef:

В C++ Builder следующее может быть сделано:

typedef void(__closure *callBackMethod)(string); 

Если вы сделаете это, я предлагаю что вы держите умный указатель на объект, к которому принадлежит член, чтобы вы могли проверить, действительно ли объект действителен до вызова функции, иначе он приведет к сбою приложения.

__closure ключевое слово является расширением C++ Builder, чтобы обойти требование использовать полные имена членов source

обрабатывать как глобальные и члены функции, которые мы имеем следующее:

typedef void(__closure *callBackMethodMember)(string); 
typedef void (*callBackMethodGlobal)(string); 

/* And then on 2 overloaded functions */ 
void addFunction(string funName, callBackMethodMember methodName) {} 
void addFunction(string funName, callBackMethodGlobal methodName) {} 
+0

Что означает '__closure'? Это стандартный C++? –

+0

Я вижу, что '__closure' является расширением C++ Builder для C++. Поэтому, если вы не используете C++ Builder, он не будет доступен. [Документы] (http://docwiki.embarcadero.com/RADStudio/XE8/en/C%2B%2B_Keyword_Extensions#closure) –

+0

Но что он делает? Там может быть стандартная эквивалентность. –

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