Я пытаюсь сделать специализацию шаблона на основе возвращаемого типа лямбда-функции, которую он получает в качестве параметра. Цель состоит в том, чтобы иметь функцию, которой я могу передать лямбду (или другую функцию, если это возможно), позволяющую функции измерять время выполнения этой лямбды и возвращать результат лямбда. Проблема возникает, когда лямбда не имеет возвращаемого значения (void).
На данный момент я использую две функции: одну для типа возврата void и вторую для всех остальных типов возврата.
template <typename F, typename ... Args>
static void measured_run(double& time, F f, Args&&...args)
{
auto start = boost::posix_time::microsec_clock::local_time();
f(std::forward<Args>(args)...);
auto end = boost::posix_time::microsec_clock::local_time();
time += (end - start).total_milliseconds();
}
template <typename F, typename ... Args>
static auto measured_run_ret_val(double & time, F f, Args&&...args) -> decltype(f(std::forward<Args>(args)...))
{
auto start = boost::posix_time::microsec_clock::local_time();
auto result = f(std::forward<Args>(args)...);
auto end = boost::posix_time::microsec_clock::local_time();
time += (end - start).total_milliseconds();
return result;
}
Я хотел бы иметь возможность использовать его следующим образом:
double time;
measured_run_ret_val(time, []() {return false; });
measured_run_ret_val(time, []() {printf("void\n"); });
Но я получаю сообщение об ошибке:
<source>: In instantiation of 'decltype (f((forward<Args>)(measured_run_ret_val::args)...)) measured_run_ret_val(double&, F, Args&& ...) [with F = main()::<lambda()>; Args = {}; decltype (f((forward<Args>)(measured_run_ret_val::args)...)) = void]':
<source>:27:25: required from here
<source>:17:10: error: 'void result' has incomplete type
17 | auto result = f(std::forward<Args>(args)...);
| ^~~~~~
<source>:20:12: error: return-statement with a value, in function returning 'void' [-fpermissive]
20 | return result;
| ^~~~~~
Сейчас я использую С++ 14, но если бы было решение в 17/20, мне бы тоже было любопытно.
Спасибо за любые предложения.
Используя C++17, вы можете использовать constexpr if для изменения логики в функции в зависимости от того, возвращает функция void
или нет. Это может выглядеть так:
template <typename F, typename ... Args>
static auto measured_run(double & time, F f, Args&&...args)
{
using ret_t = decltype(f(std::forward<Args>(args)...));
if constexpr (std::is_same_v<ret_t, void>)
{
auto start = boost::posix_time::microsec_clock::local_time();
f(std::forward<Args>(args)...);
auto end = boost::posix_time::microsec_clock::local_time();
time += (end - start).total_milliseconds();
return;
}
else
{
auto start = boost::posix_time::microsec_clock::local_time();
auto result = f(std::forward<Args>(args)...);
auto end = boost::posix_time::microsec_clock::local_time();
time += (end - start).total_milliseconds();
return result;
}
}
Вот решение C++14 godbolt.org/z/Wx5fGash5
Объект Raii тоже может помочь в этом отношении Демо