2017-09-19 1 views
0

Ich habe eine Klasse, die Callback-Funktionen registriert und sie später aufruft, die so aussieht.Erzeugen von Lambda aus der Klassenvorlage

template<typename ReturnType, typename... Args> 
class Signal { 
    std::vector<std::function<ReturnType(Args...)>> function; 
public: 
    template<typename... Args2> 
    ReturnType operator()(Args2&&... args2) { 
     ReturnType ret; 
     for (auto& func : function) 
      ret = func(std::forward<Args2>(args2)...); 
     return ret; 
    } 

    template<typename Func> 
    void func(Func const &func) { 
     function.push_back(std::function<ReturnType(Args...)>(func)); 
    } 

    template<typename Class, typename Instance> 
    void mfunc(ReturnType(Class::*func)(Args...), Instance &instance) { 
     mfunc2(func, instance, make_int_sequence<sizeof...(Args)>{}); 
    } 
    template<typename Class, typename Instance, int... I> 
    void mfunc2(ReturnType(Class::*func)(Args...), Instance &instance, int_sequence<I...>) { 
     using namespace std::placeholders; 
     function.push_back(std::function<ReturnType(Args...)>(std::bind(func, &instance, placeholder_template<I>{}...))); 
    } 
}; 

#include <iostream> 

class foo { 
public: 
    int bar(int x, double y) { 
     std::cout << x << " and " << y << std::endl; 
     return x*2; 
    } 
}; 

int main() { 
    foo foo1; 
    Signal<int, int, double> sig; 
    sig.mfunc(&foo::bar, foo1); 
    std::cout << "Return: " << sig(5,5.5) << std::endl; 
} 

hörte ich einen Vortrag von Stephan T. Lavavej heute, und eines der Dinge, die er zu sagen war, ist, dass std :: bind vermieden und stattdessen lambdas verwenden werden soll. Um etwas Neues zu lernen, dachte ich, ich würde versuchen, den Aufruf von std :: bind in mfunc2 zu einem Lambda zu ändern, aber ich bin ziemlich neu in Templates und kann nicht herausfinden, wie ich den gewünschten Code erzeuge.

Die aktuellen placeholder_template mit make_int_sequence ich hier auf SO gefunden, aber ich kann meinen Kopf nicht wirklich umschlingen, wie genau es funktioniert, oder wo auf sie jede gute Lektüre zu finden ...

Args ... enthält die Argumenttypen, die vom Lambda akzeptiert werden sollen, aber ich muss irgendwie Variablennamen wie var1, var2, var3 ect abhängig von der Größe von ... (Args) erstellen und sie dann zusammenführen.

Also zum Beispiel < int, int, int>, Args ... würde int, int halten. Ich mag dann das Lambda als

[func, &instance](int var1, int var2) -> ReturnType { return func(&instance, var1, var2); } 

konstruieren Wie könnte ich dies zu erreichen?

+0

Beginnen Sie bitte mit [mcve]. Mit etwas, das kompiliert, können wir Ihnen zeigen, wie man es ändert, um ein variadisches Lambda zu verwenden. – AndyG

+0

Ich habe meinen Beitrag bearbeitet, um den Template Specifier zu entfernen, also sollte er jetzt kompilieren, solange Sie ihm einen Return-Typ (nicht void) und mindestens 1 Argument geben. – super

Antwort

1

Dies sollte die Arbeit machen:

template<typename ReturnType, typename... Args> 
class Signal { 
    std::vector<std::function<ReturnType(Args...)>> function; 
public: 
    template<typename... Args2> 
    ReturnType operator()(Args2&&... args2) { 
     ReturnType ret; 
     for (auto& func : function) 
      ret = func(std::forward<Args2>(args2)...); 
     return ret; 
    } 

    template<typename Func> 
    void func(Func const &func) { 
     function.push_back(std::function<ReturnType(Args...)>(func)); 
    } 

    template<typename Class, typename Instance> 
    void mfunc(ReturnType(Class::*func)(Args...), Instance& instance) { 
     function.push_back([&instance, func](Args&&... args) { 
      return (instance.*func)(std::forward<Args>(args)...); 
     }); 
    } 

}; 

https://ideone.com/gjPdWN

Beachten Sie, dass in Ihrem Netzbetreiber(), können Sie grundsätzlich alle Rückgabewerte mit Ausnahme des letzten wegzuwerfen. Ist dieses Verhalten beabsichtigt?

+0

Großartig! Genau das, was ich gesucht habe. Und ja, es ist beabsichtigt, alles bis auf einen Rückgabewert wegzuwerfen, da es alles ist, was ich im Moment brauche. Ich schätze, die Werte könnten in ein std :: vector geschrieben werden und das zurückgeben, aber ich werde später etwas tun, wenn ich es brauche. – super

Verwandte Themen