2017-07-06 3 views
15

ich eine Template-Funktion haben, nennen wir es das „Client“:Wie umschließt man eine Funktion mit einer variierenden Anzahl von Standardargumenten, um nur ein Argument zu haben?

template<typename T> 
void client(T (*func)(const std::string&), const std::string& s) {} 

Dann gibt es eine Reihe von „adaptierten“ Funktionen, die alle einen identischen Typ des ersten, nicht-Standardargument, aber die Die folgenden Argumente variieren in der Anzahl und haben Standardwerte:

void adaptee_one(const std::string&, int i = 1, char* c = nullptr) {} 
void adaptee_two(const std::string&, float* f = nullptr) {} 

Die obigen Funktionen sind gegeben. Nun, was ich tun möchte ist, sie an die obige client<>() Funktion als der erste Parameter zu übergeben, und ich interessiere mich nur für die Übergabe des ersten Arguments, const std::string&. So mache ich folgendes:

void bindAdapteeOne(const std::string& s) { 
    return adaptee_one(s); 
} 

void bindAdapteeTwo(const std::string& s) { 
    return adaptee_two(s); 
} 

Und dann bindAdapteeX() zu client<>() passieren.

Was ich tun möchte ist, die Verpackung zu automatisieren oder einen (Templates) Wrapper anstelle von einem pro Adaptee zu haben. Ich denke, dies könnte für Variadics der Fall sein, aber ich habe keine Ahnung, wie man sie genau anwenden kann.

C++ 11 ist in Ordnung, C++ 14 ist in Ordnung, wenn absolut notwendig.

+0

Sind Lambdas zulässig? – AndyG

+0

@AndyG Es ist in einem Namensraum, außerhalb jeder Klasse, also denke ich ja, solange es einen gesunden Ort gibt, um sie zu behalten. – iksemyonov

+1

@rici Weil das [nicht funktioniert] (https://wandbox.org/permlink/WYzQfhLbPA7KXIEy). – Barry

Antwort

12

C++ 11 ist in Ordnung, C++ 14 ist in Ordnung, wenn absolut notwendig.

C++ 11 Lösung hier.

Was ich tun möchte ist, die Verpackung zu automatisieren oder einen (Templates) Wrapper anstelle von einem pro Adaptee zu haben.

Ich würde das nicht tun. Sie können einfach nicht erfassen lambdas verwenden und Zerfall zu Funktionszeiger lassen:

client (+[](const std::string& s) { return adaptee_one(s); }, "foo"); 

Ich glaube nicht, dass sie in Vorlage Sachen Verpackung oder was auch immer Sie würde eine Lösung, die besser lesbar oder einfach zu bedienen ist.


Als minimal, Arbeitsbeispiel:

#include<string> 

template<typename T> 
void client(T (*func)(const std::string&), const std::string& s) {} 

void adaptee_one(const std::string&, int i = 1, char* c = nullptr) {} 
void adaptee_two(const std::string&, float* f = nullptr) {} 

int main() { 
    client (+[](const std::string& s) { return adaptee_one(s); }, "foo"); 
} 
+2

Ist das "Plus" kein Tippfehler? Das habe ich noch nie zuvor gesehen. – iksemyonov

+6

@iksemyonov Es ist ein [positives lambda] (https://stackoverflow.com/questions/18889028/a-positive-lambda-what-scorery-is-this) :) Witze nur, es wird verwendet, um das Lambda in ein zu konvertieren Funktionszeiger mit Hilfe seines Konvertierungsoperators (siehe die verknüpfte Frage). – Rakete1111

+0

Danke! Heilige Kuh. Froh, dass ich diese Frage gestellt habe - hätte ich stattdessen nie gewusst. – iksemyonov

7

Dies ist eine jener Zeiten, in denen ein Makro hilft:

#define WRAP_FN(f) +[](std::string const& s) -> decltype(auto) { return f(s); } 

Obwohl Sie nur den Körper des Inline schreiben könnte statt .


Es gibt nichts, sonst könnten Sie tun. Das Problem ist, dass die Standardargumente in der Funktion der Unterschrift nicht sichtbar sind, so, wenn Sie in das Typsystem zu bekommen, gibt es keine Möglichkeit zu unterscheiden:

void works(std::string const&, int=0); 
void fails(std::string const&, int ); 

Beide von denen sind void(*)(std::string const&, int). Sie können also keine Funktionsvorlage oder keinen Klassenschablonen-Wrapper haben - Sie müssen dies inline mit einem Lambda (oder einem Makro, das ein Lambda umschließt) tun.

+0

Würde 'declltype (auto)' nicht als Rückgabetyp funktionieren? –

+0

Danke! Die Template-Lösung enthält einige Dinge, die ich nachschlagen muss, aber egal, es sieht ziemlich abscheulich aus. Keine Möglichkeit oder Notwendigkeit, variadics hier zu verwenden, um die unterschiedliche Anzahl von Argumenten zu berücksichtigen? – iksemyonov

+0

@iksemyonov Sie sagten, Sie wollten nur die 'std :: string' übergeben, wo würden Sie" variierende Anzahl von Argumenten "brauchen? –

0

Ich denke, ich würde eine Klasse erstellen, die Ihre Parameter umschließt und der Client eine Instanz dieser Klasse akzeptieren. Auf diese Weise haben Sie nur einen Parameter, der so viele Parameter enthält, wie Sie möchten.

Dieser Parameter Wrapper würde auch die Standardwerte bereitstellen und es Ihnen ermöglichen, sie in abgeleiteten Klassen für bestimmte Zwecke zu verfeinern.

Dies ist wahrscheinlich ein wenig mehr selbst-Dokumentation als auch im Vergleich zu Lambdas.

Und wer weiß, wann es Zeit ist, die Parameter aus einer Datei zu lesen und zu schreiben, dann wäre die Wrapper-Klasse der perfekte Ort dafür.

Verwandte Themen