2017-05-22 1 views
1

Folgendes ist eine grundlegende Instanz von dem, was ich in meinem C++ Programm mache. Ich habe eine Liste von Zuhörern, die alle std::function s sind. Ich habe ein Konzept DataType was bedeutet, welche Art von Daten der Hörer interessiert ist. Die Idee hier ist das gleiche wie Publish-Subscribe-Muster. Eine Methode, die an bestimmten Arten von Daten interessiert ist, sollte sich selbst zur Liste der Listener hinzufügen können, die AddListener verwenden. Einige Methoden werden hinzugefügt & sie erhalten einen Rückruf, wenn erforderlich.Wie emulieren eine templatised std :: -Funktion in C++

Das Programm funktioniert gut !!

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

Im Anschluss an die Ausgabe des Programms:

./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 

Aber hier ist, wie ich mit & kämpfen ändern möchten.Der Vorbehalt ist, dass alle ListenerMethod_Instance_1 & ListenerMethod_Instance_2 das Paar analysieren müssen, um ihre Informationen zu erhalten, die ich nicht will. Ich möchte eine Methode von jedem C++ - primitiven Datentyp aktivieren, sei es "int, bool, float oder double", um in den Listener-Vektor & den Rückruf empfangen zu können. Zum Beispiel sollte folgende Methode "add-able" in AddListener sein.

void ListenerMethod_Instance_3(int integer_data) { 

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

Blick auf diese link here sieht irgendwie möglich irgendwie. Aber ich bemühe mich, es hier an meinen Anwendungsfall anzupassen. Bitte vorschlagen.

Also, im Grunde, wie kann ich Templates Funktionalität mit std::function s erreichen?

+1

Dies könnte eine gute Verwendung für 'boost :: any' sein. – cdhowie

+1

kann keine Option von Boost verwenden. Gibt es irgendwas im 'std ::' scope, um davon zu profitieren? –

+2

@ HAL9000-Kernel Ab C++ 17 können Sie 'std :: any' verwenden. – Rakete1111

Antwort

0
struct anything_view_t { 
    void* ptr=0; 
    template<class T, std::enable_if_t<!std::is_same<anything_view_t, std::decay_t<T>>{}, int> =0> 
    anything_view_t(T&&t):ptr(std::addressof(t)){} 
    anything_view_t()=default; 
    anything_view_t(anything_view_t const&)=default; 
    anything_view_t& operator=(anything_view_t const&)=default; 
    template<class T> 
    operator T() const { return *static_cast<T*>(ptr); } 
}; 

ist dies eine sehr unsichere Art Lösch Blick auf alles.

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); 
    } 
}; 

sollte so etwas wie oben funktionieren. Der Typ T muss genau übereinstimmen. Referenzen nicht unterstützt. Code nicht kompiliert, Design ist Sound, hat wahrscheinlich Tippfehler.

Dies wird nicht in primitive Typen umgewandelt. Sie sollten T explizit überschreiten, verlassen Sie sich nicht auf Abzug, wie das fragile ist.