Ранее я использовал макрос для измерения времени, которое потребовался вызову функции, когда я хотел быстро это проверить. Теперь, когда доступен C ++ 11, я хотел бы, наконец, удалить этот уродливый код препроцессора и заменить его на что-то вроде этого:
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;
}
Что хорошо работает для функций, которые возвращают что-то (т.е. не void
). Так что я чувствовал, что мне нужна перегрузка для void
функции — но вы не можете перегрузить функцию только по типу возврата.
Я пытался обойти эту проблему, используя некоторые шаблоны магии, но безрезультатно; компилятор все еще жалуется, что функция measure
определяется два раза:
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;
}
Это можно обойти?
ОБНОВИТЬ
Вот функция, которую я сейчас использую благодаря 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)...);
}
Проблема в том, что аргументы шаблона по умолчанию не создаются для разных шаблонов, так же, как аргументы функции по умолчанию не создают для разных перегрузок. Есть несколько способов обойти это, и я описал их в своем Remastered enable_if статья.
Однако я бы не стал этого делать. Я бы просто воспользовался тем, что в общем коде вы можетеreturn
void «, и используйте RAII, чтобы распечатать истекшее время:
template <typename Functor, typename ... Args>
auto measure(Functor f, Args && ... args)
-> decltype(f(std::forward<Args>(args)...))
{
scoped_timer timer;
return f(std::forward<Args>(args)...);
}
scoped_timer
класс можно написать тривиально: сохранить now
в конструкторе, а также вычислять и выводить elapsed
в деструкторе.
Других решений пока нет …