2015-07-06 17 views
7

Un frammento di codice che ho visto in Effective C++ moderno dispone di un'implementazione intelligente del instrumentation rationale per creare un funzione timer:Quando dovrei std :: inoltrare una chiamata di funzione?

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

La mia domanda riguarda std::forward<decltype(func)>(func)(...

  • Per la mia comprensione, siamo in realtà casting la funzione al suo tipo originale, ma perché è necessario? Sembra che una semplice chiamata farebbe il trucco.
  • Esistono altri casi in cui si utilizza l'inoltro perfetto per effettuare una chiamata di funzione?

Questo appare come un buon caso d'uso per the use of familiar template syntax in lambda expressions nel caso in cui abbiamo voluto fare il tipo di timer una costante di tempo di compilazione.

+0

penso che potrebbe essere perché 'func' possibile grande oggetto funzione con un operatore non-const(). In questo modo, si evita di copie inutili e lasciate mutazione del l'oggetto funzione – KABoissonneault

+1

Il tipo * * dell'espressione non cambia con il cast, ma la sua categoria * * valore non. Questo è l'intero e solo [punto di 'forward'] (http://stackoverflow.com/a/13219621). –

+4

L'intento è quello di assicurarsi il corretto [ref-qualificati] (http://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions) Sovraccarico di 'operatore()' è scelto –

risposta

9

Una migliore descrizione di ciò che sta facendo std::forward<decltype(func)>(func)(...) sarebbe preservare la categoria valore dell'argomento passato alla lambda.

Si consideri il seguente funtore con Ref-qualificato operator() sovraccarichi.

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

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

Ricordate che all'interno del corpo del lambda func è un lvalue (because it has a name). Se non si è forward l'argomento della funzione il sovraccarico qualificato && non può mai essere invocato. Inoltre, se il sovraccarico & qualificati erano assenti, quindi, anche se il chiamante si passa un'istanza rvalue foo, il codice fallirebbe per la compilazione.

Live demo

+0

Sei d'accordo che il 'decltype (func)' parte è necessaria solo in lambda generici in mancanza di informazioni tipo è precisato per 'func'? Se questo è il caso potrei scrivere 'std :: avanti (func) (...)' 'per modello vuoto Foo (F && func)' e fare la stessa cosa giusta? –

+0

@NikosAthanasiou Sì, farebbe la stessa cosa – Praetorian