一些通用的代码操作函数,需要根据函数是否有返回值来进行不同的操作。例如,从这个问题中借用一个问题,假设我们需要编写一个time_it
函数,接受一个函数和一些参数,运行它,并打印经过的时间。下面的代码可以做到这一点:
#include <chrono>
#include <type_traits>
#include <cmath>
#include <iostream>
template<class Fn, typename ...Args>
auto time_it(Fn fn, Args &&...args) ->
typename std::enable_if<
!std::is_void<typename std::result_of<Fn(decltype(std::forward<Args>(args))...)>::type>::value,
typename std::result_of<Fn(decltype(std::forward<Args>(args))...)>::type>::type
{
const auto start = std::chrono::system_clock::now();
auto const res = fn(std::forward<Args>(args)...);
const auto end = std::chrono::system_clock::now();
std::cout << "elapsed " << (end - start).count() << std::endl;
return res;
}
template<class Fn, typename ...Args>
auto time_it(Fn fn, Args &&...args) ->
typename std::enable_if<
std::is_void<typename std::result_of<Fn(decltype(std::forward<Args>(args))...)>::type>::value,
void>::type
{
const auto start = std::chrono::system_clock::now();
fn(std::forward<Args>(args)...);
const auto end = std::chrono::system_clock::now();
std::cout << "elapsed " << (end - start).count() << std::endl;
}
int main()
{
time_it([](double x){return std::cos(x);}, 3.0);
time_it([](double x){}, 3.0);
}
可以看出,函数返回值与否的情况是有区别的。在前一种情况下,必须存储值,打印经过的时间,并返回值;在后一种情况下,打印经过的时间后,无需再做任何事情。
问题是如何处理这两种情况:
上面的代码使用
std::enable_if
andis_void
,但是第一个(本身很麻烦)参数is_void
被重复作为最后一个参数enable_if
- 这很麻烦并且有味道,尤其是。尽可能多的身体重复。上述答案通过将经过的时间打印为调用某个经过的计时器类的析构函数的副产品来绕过该问题。这是个好主意,但在更复杂的用途中会导致代码复杂(大量工作是在某个单独类的析构函数中完成的——这不是自然流程)。
有没有更好的方法来做到这一点?