Идеальная пересылка для пустых и не пустых функций возврата

Ранее я использовал макрос для измерения времени, которое потребовался вызову функции, когда я хотел быстро это проверить. Теперь, когда доступен 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)...);
}

9

Решение

Проблема в том, что аргументы шаблона по умолчанию не создаются для разных шаблонов, так же, как аргументы функции по умолчанию не создают для разных перегрузок. Есть несколько способов обойти это, и я описал их в своем 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 в деструкторе.

14

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]