2017-02-25 2 views
0

Ich versuche, ein Programm zu schreiben, das eine Funktion mit einer beliebigen Anzahl von Parametern akzeptiert und sie mit std :: bind auf eine Funktion reduziert, die nur einen Parameter akzeptiert.Funktion Überladungen, um alle Arten von Funktionen zu akzeptieren

Der letzte Teil des Problems ist in Ordnung, aber ich möchte der Benutzer in der Lage sein, jede Art von Funktion eingeben - std :: Funktion, Funktionszeiger, Funktor oder Lambda - und ich weiß nicht, wie man eine Vorlage schreibt Parameter, der die letzten beiden Typen akzeptiert und es mir erlaubt, die Anzahl der Argumente abzuleiten, die die Funktion benötigt.

Beispielcode mit einer 'foo' Funktion, die überladen ist, um Funktionszeiger und std :: Funktionen zu akzeptieren - wenn mir jemand in die richtige Richtung zeigen könnte, wie die anderen beiden Überladungen geschrieben werden, wäre ich sehr dankbar.

#include <functional> 
#include <iostream> 

template <typename Ret, typename ParamA, typename... Params> 
unsigned int foo(const std::function<Ret(ParamA, Params...)>& f) 
{ 
    return sizeof...(Params); 
} 

template <typename Ret, typename ParamA, typename... Params> 
unsigned int foo(Ret(*f)(ParamA, Params...)) 
{ 
    return sizeof...(Params); 
} 

unsigned int foo(/*accepts a functor*/); 

unsigned int foo(/*accepts a lambda*/); 

std::function<void(int)> std_func([](int) {}); 
void f_ptr(int, int) {} 
struct functor { void operator() (int, int, int) {} }; 
auto lambda = [](int, int, int, int) {}; 

int main() 
{ 
    std::cout << foo(std_func); //Passed in a std::function 
    std::cout << foo(f_ptr); //Passed in a function pointer 
    std::cout << foo(functor()); //Passed in a functor 
    std::cout << foo(lambda); //Passed in a lambda 

    return 0; 
} 
+0

Das Problem ist nicht klar definiert. Ein Funktor (eine Klasse mit 'operator()') kann mehrere Überladungen von 'operator()' bereitstellen, indem er unterschiedliche Anzahl und Typen von Parametern annimmt. Auf welche von ihnen soll Ihre Funktion reagieren? –

+0

Sie müssen sich darüber keine Gedanken machen, da 'std :: bind 'die Parameter jedes aufrufbaren Objekts bindet. Eine Sache, die Sie noch nicht vollständig erklärt haben, ist, an was genau Sie jeden Parameter binden möchten. Sie können einen Parameter nicht einfach an etwas Nichtspezifisches binden. Der ganze Zweck von 'std :: bind 'besteht darin, dem Funktionsparameter einen diskreten Wert zuzuweisen. Also, was genau willst du binden? –

+0

@SamVarshavchik Zum Beispiel möchte ich vielleicht Funktionen akzeptieren, die ganzzahlige Parameter annehmen und die Position des Parameters an sie binden, zum Beispiel foo (int a, int b, int c) würde foo werden (int a, 1, 2) –

Antwort

0

Etwas wie folgt aus:

// Accepts a pointer to member function 
template <typename T, typename Ret, typename ParamA, typename... Params> 
unsigned int foo(Ret (T::*f)(ParamA, Params...)) 
{ 
    return sizeof...(Params); 
} 

// Accepts a pointer to const member function 
template <typename T, typename Ret, typename ParamA, typename... Params> 
unsigned int foo(Ret (T::*f)(ParamA, Params...) const) 
{ 
    return sizeof...(Params); 
} 

// Accepts a function object, including lambda and std::function 
template <typename F> 
unsigned int foo(const F& func) { 
    return foo(&F::operator()); 
}  

Nur auf einem Funktionsobjekt arbeitet mit einem, nicht überlastet operator(). Da std::function auch ein solches Objekt ist, ist die dedizierte Überladung für std::function nicht mehr notwendig (aber eine für den einfachen Funktionszeiger wird noch benötigt).

Demo

Verwandte Themen