2017-05-22 1 views
1

다음은 내 C++ 프로그램에서 수행중인 작업의 기본 인스턴스입니다. 나는 청취자 목록이 모두 std::function입니다. 저는 청취자가 어떤 종류의 데이터에 관심이 있는지를 의미하는 개념 DataType을 가지고 있습니다. 여기의 아이디어는 publish-subscribe 패턴과 같습니다. 특정 종류의 데이터에 관심이있는 메소드는 AddListener을 사용하여 리스너 목록에 자신을 추가 할 수 있어야합니다. 일부 메서드는 필요할 때마다 & 콜백을받습니다.C++에서 templatised std :: function을 에뮬레이트하는 방법

프로그램이 정상적으로 작동합니다. 다음

#include <iostream> 
#include <functional> 
#include <vector> 
#include <string> 

enum class DataType { 
    Type_1, 
    Type_2 
    // and so on 
}; 

typedef std::function<void(std::pair<DataType, std::string>)> MyListenerType; 

//template <typename T> 
//typedef std::function<void(T>)> MyListenerType; 
// How can I emulate the above so that a method passing any kind of primitive data-type namely "int, bool, float or double" can be added into 
// my vector of listners. 


std::vector<MyListenerType>  my_data_listeners_1; 
std::vector<MyListenerType>  my_data_listeners_2; 

void ListenerMethod_Instance_1(std::pair<DataType, std::string> information) { 

    DataType data_type = information.first; 
    std::string message = information.second; 
    std::cout << "ListenerMethod_Instance_1 called with message " << message << "\n"; 
} 

void ListenerMethod_Instance_2(std::pair<DataType, std::string> information) { 

    DataType data_type = information.first; 
    std::string message = information.second; 
    std::cout << "ListenerMethod_Instance_2 called with message " << message << "\n"; 
} 

void AddListener (MyListenerType listener, DataType type_of_interest) { 

    if (DataType::Type_1 == type_of_interest) { 
    my_data_listeners_1.push_back(listener); 
    std::cout << "Added a method instance for DataType::Type_1" << "\n"; 
    } 
    else if (DataType::Type_2 == type_of_interest) { 
    my_data_listeners_2.push_back(listener); 
    std::cout << "Added a method instance for DataType::Type_2" << "\n"; 
    } 
    else { 
    std::cout << "Listener type not supported" << "\n"; 
    } 
} 

void CallAllListnersWhohaveSuscribed() { 

    if (!my_data_listeners_1.empty()) { 
    std::string send_message_1 = "some message 123"; 
    std::pair <DataType, std::string> info_to_send_1 = std::make_pair (DataType::Type_1, send_message_1); 
    for(auto const &listener : my_data_listeners_1) { 
     listener(info_to_send_1); 
    } 
    } 

    if (!my_data_listeners_2.empty()) { 
    std::string send_message_2 = "some message 456"; 
    std::pair <DataType, std::string> info_to_send_2 = std::make_pair (DataType::Type_2, send_message_2); 
    for(auto const &listener : my_data_listeners_2) { 
     listener(info_to_send_2); 
    } 
    } 
} 

int main() { 

    // Add ListenerMethod_Instance_1 for instance 
    DataType data_type_1 = DataType::Type_1; 
    auto listener_instance_1 = std::bind(ListenerMethod_Instance_1, std::placeholders::_1); 
    AddListener(listener_instance_1, data_type_1); 

    // Add ListenerMethod_Instance_2 for instance 
    DataType data_type_2 = DataType::Type_2; 
    auto listener_instance_2 = std::bind(ListenerMethod_Instance_2, std::placeholders::_1); 
    AddListener(listener_instance_2, data_type_2); 

    CallAllListnersWhohaveSuscribed(); 
    return 0; 
} 

프로그램의 출력 :

./stdFunctionTest 
Added a method instance for DataType::Type_1 
Added a method instance for DataType::Type_2 
ListenerMethod_Instance_1 called with message some message 123 
ListenerMethod_Instance_2 called with message some message 456 

그러나 여기에 내가 고민 &을 수정하는 방법입니다.주의 할 점은 각 ListenerMethod_Instance_1 & 은 쌍을 구문 분석하여 원하지 않는 정보를 가져와야한다는 것입니다. 모든 C++ 기본 데이터 형식의 메서드를 "int, bool, float 또는 double"로 설정하여 수신기 벡터에 추가 할 수 있습니다. & 콜백을 수신합니다. 예를 들어, 다음의 메소드는 AddListener에 "add-able"해야합니다.

void ListenerMethod_Instance_3(int integer_data) { 

    std::cout << "ListenerMethod_Instance_3 called with integer_data " << integer_data << "\n"; 
} 

link here은 다소 다소 다를 수 있습니다. 그러나 나는 그것을 여기의 나의 유스 케이스에 맞추기 위해 고심하고있다. 제발 제안 해주세요.

기본적으로 어떻게 std::function s의 템플릿 기능을 얻을 수 있습니까?

+1

이것은 'boost :: any'에 유용 할 수 있습니다. – cdhowie

+1

부스트에서 옵션을 사용할 수 없습니다. 'std ::'범위에서 사용할 수있는 것이 있습니까? –

+2

@ HAL9000-Kernel C++로 시작하면'std :: any'를 사용할 수 있습니다. – Rakete1111

답변

0

이것은 매우 안전하지 않은 유형의 항목입니다.

struct any_callbacks { 
    std::unordered_map<std::type_index, std::vector<std::function<void(anything_view_t)>>> table; 
    template<class T> 
    void add_callback(std::function<void(T)> f){ 
    table[typeid(T)].push_back(f); 
    } 
    template<class T> 
    void invoke_callbacks(T t) const { 
    auto it = table.find(typeid(T)); 
    if (it==table.end()) return; 
    for(auto&&f:it->second) 
     f(t); 
    } 
}; 

위와 같이 동작해야합니다. 유형 T은 정확히 일치해야합니다. 참조가 지원되지 않습니다. 코드가 컴파일되지 않았으며, 디자인이 정상적으로 작동하고 오타가있을 수 있습니다.

이것은 기본 유형으로 재구성되지 않습니다. T을 명시 적으로 전달해야합니다. 연체에 의존하지 마시고 깨지기 쉽습니다.

관련 문제