2015-07-06 15 views
7

Ein Codeausschnitt I in Effektive Moderne C sah ++ hat eine clevere Umsetzung der instrumentation rationale eine Funktion Timer zu erstellen:Wann sollte ich :: einen Funktionsaufruf weiterleiten?

auto timeFuncInvocation = 
    [](auto&& func, auto&&... params) 
    { 
     start timer; 
     std::forward<decltype(func)>(func)(
      std::forward<decltype(params)>(params)...); 
     stop timer and record elapsed time; 
    }; 

Meine Frage ist über std::forward<decltype(func)>(func)(...

  • Zu meinem Verständnis, wir sind tatsächlich Casting die Funktion zu seinem Original Typ, aber warum wird das gebraucht? Es sieht aus wie ein einfacher Anruf würde den Trick tun.
  • Gibt es noch andere Fälle, in denen wir eine perfekte Weiterleitung verwenden, um einen Funktionsaufruf zu tätigen?

Das sieht wie ein guter Anwendungsfall für the use of familiar template syntax in lambda expressions falls wir die Timer-Typ eine Kompilierung konstant machen wollte.

+0

denke ich es, weil 'func' kann mit einem nicht-const-Operator() großes Funktionsobjekt sein könnte. Auf diese Weise vermeiden Sie sinnlose Kopien und erlauben eine Mutation des Funktionsobjekts – KABoissonneault

+1

Der * Typ * des Ausdrucks ändert sich nicht mit der Besetzung, aber seine * Wertkategorie * tut es. Das ist das Ganze und nur [von vorne] (http://stackoverflow.com/a/13219621). –

+4

Die Absicht ist, die korrekte [ref-qualifizierte] (http://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions) Überladung von 'operator()' sicherzustellen ist gewählt. –

Antwort

9

Eine bessere Beschreibung dessen, was std::forward<decltype(func)>(func)(...) ist würde dabei sein den Wert Kategorie des an die Lambda-gebene Argument zu erhalten.

Betrachten Sie den folgenden Funktor mit ref-qualifizierten operator() Überladungen.

struct foo 
{ 
    void operator()() const && 
    { std::cout << __PRETTY_FUNCTION__ << '\n'; } 

    void operator()() const & 
    { std::cout << __PRETTY_FUNCTION__ << '\n'; } 
}; 

Denken Sie daran, dass innerhalb des Körpers des Lambda func ist ein L-Wert (because it has a name). Wenn Sie das Funktionsargument nicht forward haben, kann die && qualifizierte Überladung nie aufgerufen werden. Wenn außerdem die qualifizierte Überlastung & nicht vorhanden war, konnte Ihr Code auch dann nicht kompiliert werden, wenn der Anrufer Ihnen eine rvalue foo -Instanz übergeben hat.

Live demo

+0

Würdest du zustimmen, dass der 'declltype (func)' Teil nur in generischen lambdas benötigt wird, wo keine Typinformationen für 'func' geschrieben sind? Wenn das der Fall ist, könnte ich schreiben 'std :: forward (func) (...)' für 'Vorlage void Foo (F && func)' und die gleiche Sache richtig? –

+0

@NikosAthanasiou Ja, das würde das Gleiche tun – Praetorian

Verwandte Themen