2015-12-14 9 views
6

mit folgenden FunktionenParametrieren Vorlage von Funktionsnamen C++ 11

void print(int a) { cout << a << endl; } 
void print(std::string a) { cout << a << endl; } 

Sie können

template <class T> void printT(T a) { print(a); } 

Gibt es die folgende Vorlage tun einige Mechanismus, um die Funktionsnamen parametrisieren? Etwas wie folgt aus:

template <class T, class F> void anyT(T a) { F(a); } 

Ich brauche nicht eine Funktionsvorlage sein, nur einen Mechanismus, das gleiche zu erreichen.

+1

nur für Neugier: Warum willst du das machen? Ist es nicht schön, in der Lage zu sein, 'print (x);' zu schreiben, wobei 'x'' string' oder 'int' sein kann, anstatt den Typ anzugeben (dh' (x) 'für' int') und 'print (x)' für Strings)? – user463035818

+0

@ tobi303, müssen Sie in diesem Fall den Schablonentyp nicht angeben. Der Compiler kann dies recht einfach ableiten. – StoryTeller

+0

@ tobi303 Ich weiß. Es ist nur ein Spielzeug-Beispiel, um das Problem vorzustellen und die Dinge zu erleichtern, die helfen wollen. Ich hasse es wirklich, wenn einige Leute den ganzen Code einfügen, wenn es nicht wirklich benötigt wird. –

Antwort

1

Ja, können Sie den Anrufer als Funktionszeiger übergeben, die T wie unten als Eingabe:

template <class T> void anyT(T a, void(*f)(T)) { 
    f(a); 
} 

Live Demo

+0

Der down-voter erklärt ... – 101010

+2

Ich habe nicht downvote, aber vielleicht wäre es am besten, nicht die Signatur des zu spezifizieren Funktion und haben nur einen Template-Parameter dafür. Auf diese Weise kann die Signatur unterschiedlich sein (zB 'const T &') und Funktoren sind ebenfalls erlaubt. – SirGuy

+0

Danke !. Funktioniert perfekt. –

0

kämpfen, um die Gründe hier zu verstehen. In C++ 14 haben wir Lambdas mit automatischen Argumenten. Wird das das lösen?

#include <iostream> 

int main() { 


    int a = 1; 
    std::string str = "string"; 

    auto print = [] (const auto& a) { std::cout << a << std::endl; }; 

    print(a); 
    print(str); 
} 
1

Sie können die Funktion als Parameter übergeben.

template <class T, class F> 
void anyT(T a, F f) { 
    f(a); 
} 

Dies hat der Vorteil im Vergleich zu einem Funktionszeiger mit Templat-Argumente Typ von 101010 vorgeschlagen vorbei ist, dass dies auch als functors (Instanzen von jeder Art mit Funktionszeiger arbeitet, die operator() wie Lambda-Ausdrücke implementieren.

der Nachteil besteht darin, dass ein Funktionszeiger einer überladene Funktion immer im Zusammenhang mit dem frei Templat Parameter kann schwierig sein. Sie bräuchten

void (*f)(int) = print; 
anyT(a, f); 

Oder alternativ, wickeln Sie es in einem Lamm verwenden wie von GuyGreer vorgeschlagen.

1

Ich persönlich würde mit 101010 Lösung gehen, aber Sie scheinen nicht den Funktionszeiger als Funktionsparameter, sondern nur als Vorlageparameter übergeben möchten. Hier ist, wie können Sie das tun:

#include <string> 

    template <class T, void(*func)(T)> 
    void anyT(T t) 
    { 
     func(t); 
    } 

    void print(int i){} 
    void print(std::string s){} 

    int main() 
    { 
     anyT<int, print>(1); 
     anyT<std::string, print>("hello"); 
    } 

Leider ist es bedeutet, dass Sie die Template-Parameter für die Funktion jedes Mal angegeben werden, die eine Drag ist.

Die bessere Lösung Ich denke, wäre, nur einen generischen Template-Parameter zu verwenden und eine Lambda:

template <class T, class F> 
    void anyT(T t, F f) 
    { 
     f(t); 
    } 

    auto printT = [](auto i){print(i);} 
    anyT(0, printT); 

Das Lambda ist notwendig, da vorbei print direkt mehrdeutig sein würde, wird der Compiler nicht wissen, ob Sie bedeuten print(int) oder print(std::string).

1

Dies ist ein nützliches Makro:

#define OVERRIDES_OF(...) [](auto&&...args)->decltype(auto){ return __VA_ARGS__ (decltype(args)(args)...);} 

das Ergebnis ist ein stateless Lambda, die zur Verfügung gestellt, um die Token weiterleitet.

Verwendung:

static const auto printT = OVERRIDES_OF(print); 

jetzt printT ist ein Objekt, das alle der Überschreibungen von print hüllt.

+0

Sie scheinen ein 'Auto' zu verpassen. Unabhängig davon, machen Sie das Makro variadic, um Dinge wie 'OVERRIDES_OF (f <1,2,3>)' zu unterstützen? Ich kann mir keinen anderen Grund vorstellen, aber ich glaube, ich kann es genauso gut fragen. – SirGuy

+0

@guygreer können Sie Override-Sets als einzelne Objekte mit dieser Technik umgehen. Anstatt eine Überschreibung angeben zu müssen. – Yakk

+0

Sätze außer Kraft setzen?Ich bin mir nicht sicher, ob ich verstehe – SirGuy

0

Sie können die Funktion über einen Funktionszeiger übergeben:

template <class T> void anyT(T a, void(*F)(T)) { F(a); } 

aber dann kann man nicht einen Lambda-Pass:

auto printStr = [](std::string a) { cout << a << endl; }; 
anyT(foo, printStr); // This won't compile 

Ein alternativer Ansatz wäre std::function zu verwenden:

template <class T> 
void anyT(T a, std::function<void(T)> F) { F(a); } 

oder ein generischer Vorlagenparameter:

template <class T, class F> 
void anyT(T a, F func) { func(t); } 

Dies hat den Nachteil, dass es nicht überladene Funktionen lösen können, aber Sie können eine Hilfsfunktion verwenden:

template<typename F> 
std::function<F> make_function(F *funPtr) { 
    return std::function<F>(static_cast<F*>(funPtr)); 
} 

und anyT wie folgt aufrufen:

string foo = "foo"; 
anyT(foo, make_function<void(std::string)>(&print));