Können wir den Typ eines lambda-argument?
Mit std::function
können wir die Art von argument mit der argument_type
, second_argument_type
etc. typedefs, aber ich kann nicht einen Weg finden, das gleiche zu tun, mit lambdas. Ist es möglich? (Ich verwende VS2010)
Sagen, ich will sowas wie das folgende in meine Deserialisierung system dient zum Lesen eines Objekt und übergeben es an eine setter-Funktion:
template<typename F>
static void forward(F f)
{
//Create an object of the type of the first
//parameter to the function object F
typedef typename F::argument_type T;
T t;
//...do something with 't' here (deserialize in my case)
//Forward the object to the function
f(t);
}
Es verwendet werden kann, wie dies und alles funktioniert einwandfrei:
std::function<void(int)> f = [](int i) -> void { setValue(i); };
forward(f);
Aber es arbeitet nicht direkt mit lambdas:
forward([](int i) -> void { setValue(i); });
//error C2039: 'argument_type' : is not a
//member of '`anonymous-namespace'::<lambda1>'
Gibt es eine Möglichkeit, den Zugriff auf die parameter-Typen in einer Weise, die die Arbeit für beide lambdas und std::function
Objekte? Vielleicht ein Weg, um die std::function
Typ eines lambda-zuerst, und dann die argument_type
aus?
Folgenden sich aus der Antwort unten eine version, die funktioniert mit lambdas und std::function
ist:
template<typename T, typename F>
static void forward(F f)
{
T t;
//...do something with 't' here (deserialize in my case)
f(t);
}
forward<int>([](int i) -> void { setValue(i); });
Seit int
ist hier wiederholt ich hatte gehofft, es loszuwerden - gar nicht so schlecht für int
aber mehr ärgerlich für lange Namen von Typen in ein paar namespaces. C ' est la vie!
Lange Antwort: ja, siehe unten.
InformationsquelleAutor Chris Caulfield | 2011-06-28
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist nicht wünschenswert, im Allgemeinen Fall. (Beachten Sie, dass es ziemlich leicht für
std::function<T(A)>
angeben, was z.B.argument_type
ist: es ist nurA
! Es ist erhältlich in der type-definition.)Wäre es möglich zu verlangen, dass jeder und jede Funktion Objekttyp geben Sie die argument-Typen, und im Gegenzug verlangen, dass die Schließung Typen, generiert aus den lambda-Ausdruck tun. In der Tat, pre-C++0x-features wie anpassungsfähig funktoren würde nur Arbeit für solche Typen.
Jedoch, bewegen wir uns aus, dass mit C++0x und das mit guten Gründen. Der einfachste von denen ist einfach überladen: Funktor-Typ mit einem Vorlagen -
operator()
(ein.k.a eine polymorphe functor) nimmt einfach alle Art von Argumenten; so was sollteargument_type
werden? Ein weiterer Grund ist, dass generischer code (in der Regel) versucht, geben die wenigsten Einschränkungen für die Typen und Objekte, die es betreibt, um leichter (wieder)verwendet.In anderen Worten, generischen code ist nicht wirklich interessiert, dass angesichts der
Functor f
,typename Functor::argument
werdenint
. Es ist viel mehr interessant zu wissen, dassf(0)
ist eine zulässige Meinungsäußerung. Für dieses C++0x gibt tools wiedecltype
undstd::declval
(günstiger Verpackung die zwei instd::result_of
).So wie ich das sehe haben Sie zwei Möglichkeiten: - verlangen, dass alle funktoren übergeben, um Ihre Vorlage verwenden ein C++03-style-convention der Angabe einer
argument_type
und dergleichen; verwenden Sie die Technik unten; oder Neugestaltung. Ich würde empfehlen die Letzte option, aber es ist Ihr Anruf, da ich nicht weiß, was Ihre Codebasis aussieht oder was Ihre Anforderungen sind.Für eine monomorphe Funktor-Typ (also keine überlastung), es ist möglich, zu kontrollieren, die
operator()
Mitglied. Dies funktioniert für die Schließung Arten von lambda-Ausdrücken.So erklären wir diese Helfer
akzeptieren, dass ein Zeiger auf member-Funktion, die mindestens ein argument. Und jetzt:
[ ein ausgeklügeltes Merkmal könnte die sukzessive Abfrage der lvalue-rvalue/const/volatile überlastungen und setzen Sie das erste argument, wenn es das gleiche für alle überladungen, oder verwenden Sie
std::common_type
.]Mein code der tatsächlich erfassten Variablen (in der Regel das Objekt, nach dem Aufruf der setter-Methode), aber danke für die Klarstellung.
Sollten Sie nicht in der Lage sein, etwas ähnliches zu tun, aber mit
&F::operator()
- und Zeiger-auf-member-Funktionen anstelle der AnalyseF
direkt? Das wäre für die Lambda-Ausdrücke, die Sie akzeptieren erfasst als auch, würde ich denken.Hah, ja, das ist erlaubt. Ich hoffe, dass meine Umschreibung wird mich nicht vergessen, über die Technik wieder.
Beachten Sie, dass mit C++17, können Sie
std::function
's Abzug guides. Intern, entweder Sie verwenden Funktionszeiger oder Prüfung der Art deroperator()
. Dies kann leicht kombiniert werden mit einer manuellen Typ Merkmal zu extrahieren, die Argumente und den Rückgabetyp.InformationsquelleAutor Luc Danton
@Luc ' s Antwort ist Super, aber ich kam gerade über einen Fall, wo ich auch notwendig, um Funktionszeiger:
Dies kann verwendet werden, auf beiden funktoren und Funktionszeiger:
InformationsquelleAutor Till Varoquaux