Precedentemente stavo usando una macro per misurare l'ora in cui una chiamata di funzione ha avuto luogo ogni volta che volevo controllare rapidamente. Ora, con il C++ 11 a disposizione, vorrei cancellare finalmente quel brutto pace del codice preprocessore e sostituirlo con qualcosa di simile:Inoltro perfetto per le funzioni di restituzione void e non vuoto
template <typename Functor, typename ... Args>
auto measure(Functor f, Args && ... args)
-> decltype(f(std::forward<Args>(args)...))
{
auto now = std::chrono::high_resolution_clock::now();
auto ret = f(std::forward<Args>(args)...);
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - now).count();
std::cout << "Time elapsed: " << elapsed << "ms" << std::endl;
return ret;
}
che funziona bene per le funzioni che restituiscono qualcosa (vale a dire non void
). Quindi mi sentivo come se avessi bisogno di un sovraccarico per le funzioni void
- ma non è possibile sovraccaricare una funzione solo sul tipo restituito.
Ho cercato di aggirare questo problema utilizzando alcuni modelli di magia, ma senza successo; il compilatore si lamenta ancora che la funzione measure
è definita due volte:
template <
typename Functor, typename ... Args,
typename ReturnType = typename std::enable_if<
!std::is_void<
typename std::result_of<Functor(Args...)>::type
>::value,
typename std::result_of<Functor(Args...)>::type
>::type
>
ReturnType measure(Functor f, Args && ... args)
{
auto now = std::chrono::high_resolution_clock::now();
auto ret = f(std::forward<Args>(args)...);
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - now).count();
std::cout << "Time elapsed: " << elapsed << "ms" << std::endl;
return ret;
}
template <
typename Functor, typename ... Args,
typename ReturnType = typename std::enable_if<
std::is_void<
typename std::result_of<Functor(Args...)>::type
>::value
>::type
>
ReturnType measure(Functor f, Args && ... args)
{
auto now = std::chrono::high_resolution_clock::now();
f(std::forward<Args>(args)...);
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - now).count();
std::cout << "Time elapsed: " << elapsed << "ms" << std::endl;
}
Esiste un modo per aggirare questo?
UPDATE
Ecco la funzione ora sto usando grazie a R. Martinho Fernandes:
template <typename Functor, typename ... Args>
auto measure(Functor f, Args && ... args)
-> decltype(f(std::forward<Args>(args)...))
{
struct scoped_timer
{
scoped_timer() : now_(std::chrono::high_resolution_clock::now()) {}
~scoped_timer()
{
auto elapsed = std::chrono::duration_cast<
std::chrono::milliseconds
>(std::chrono::high_resolution_clock::now() - now_).count();
std::cout << "Time elapsed: " << elapsed << "ms" << std::endl;
}
private:
std::chrono::high_resolution_clock::time_point const now_;
} scoped_timer;
return f(std::forward<Args>(args)...);
}
Vedere http://flamingdangerzone.com/cxx11/2012/06/01/almost-static-if.html#evolution –
Elegante [idea] (http://stackoverflow.com/a/17748197/1137388) (di [R. Martinho Fernandes] (http://stackoverflow.com/users/46642/r-martinho-fernandes)). L'unica modifica che farei sarebbe posizionare il codice '~ scoped_timer()' in un blocco 'try-catch' che ingoia qualsiasi eccezione generata. Semanticamente, credo che abbia senso non riportare il tempo che 'f' impiega a correre se non si completa con successo. Sfortunatamente, questo non è così ovvio riguardo alle possibili eccezioni generate da << << '. Un vecchio 'printf' sarebbe un'alternativa migliore (per quanto riguarda la sicurezza delle eccezioni)? Non lo so. –