如何在返回第二个值的同时完善从函数返回的值?
How to perfect forward a value returned from a function while returning a second value?
我想制作一个 benchmark
函数,给定一个可调用对象及其参数,将对给定可调用对象和 return 测量的 std::chrono::duration<...>
以及值 return 由可调用对象的调用编辑。
我在完美转发调用中 return 的值时遇到问题。目前我 return 值 return 通过调用编辑并使用参考参数 return 持续时间:
using bench_clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock, std::chrono::steady_clock>;
decltype(auto) benchmark(
bench_clock::duration& duration, auto&& func, auto&&... args)
{
auto begin{ bench_clock::now() };
decltype(auto) result{
std::invoke(
std::forward<decltype(func)>(func),
std::forward<decltype(args)>(args)...)
};
duration = bench_clock::now() - begin;
return result;
}
据我所知,这完美地转发了调用中 returned 的值。
我更愿意按照惯例 return 持续时间,例如,通过使用 std::tuple
虽然我不确定如何做到完美转发 returned 值.
我的猜测是像这样使用 std::invoke_result_t
:
using bench_clock = std::conditional_t<
std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock, std::chrono::steady_clock>;
auto benchmark(auto&& func, auto&&... args)
{
auto begin{ bench_clock::now() };
decltype(auto) result{
std::invoke(
std::forward<decltype(func)>(func),
std::forward<decltype(args)>(args)...)
};
auto duration{ bench_clock::now() - begin };
return std::tuple<std::invoke_result_t<decltype(func), decltype(args)...>, bench_clock::duration>{std::forward<decltype(result)>(result), duration};
//------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ is this needed?
}
我不确定这种方法是否正确完美转发。我也不知道是否需要在 std::tuple
构造函数中使用 std::forward
。
还有一个问题,如果可调用returns void
,元组不能使用,因为std::tuple<void>
不能实例化。
我不确定如何解决这个问题。
是的,你是对的。在 benchmark
函数中调用函数 func
时,需要处理 void
return 的情况。
由于您使用了 std::invoke_result_t
和 std::conditional_t
,我假设您可以访问 c++17. Then this can be easily solved by an if constexpr
检查。
#include <iostream>
#include <chrono>
#include <tuple>
#include <type_traits> // std::is_same_v, std::invoke_result_t
#include <functional> // std::invoke
#include <utility> // std::forward, std::move
using namespace std::chrono;
using bench_clock = std::conditional_t<
high_resolution_clock::is_steady, high_resolution_clock, steady_clock>;
template<typename Func, typename... Args>
decltype(auto) benchmark(Func&& func, Args&&... args)
{
auto begin{ bench_clock::now() };
if constexpr (std::is_same_v<void, std::invoke_result_t<Func, Args...>>)
{
// can not have void result: therefore just invoke the func!
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
return bench_clock::now() - begin; // only the time duration will be returned!
}
else
{
// all other cases return the tuple of result-duration!
decltype(auto) result{ std::invoke(std::forward<Func>(func), std::forward<Args>(args)...) };
const auto duration{ bench_clock::now() - begin };
return std::make_tuple(std::move(result), duration);
}
}
我想制作一个 benchmark
函数,给定一个可调用对象及其参数,将对给定可调用对象和 return 测量的 std::chrono::duration<...>
以及值 return 由可调用对象的调用编辑。
我在完美转发调用中 return 的值时遇到问题。目前我 return 值 return 通过调用编辑并使用参考参数 return 持续时间:
using bench_clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock, std::chrono::steady_clock>;
decltype(auto) benchmark(
bench_clock::duration& duration, auto&& func, auto&&... args)
{
auto begin{ bench_clock::now() };
decltype(auto) result{
std::invoke(
std::forward<decltype(func)>(func),
std::forward<decltype(args)>(args)...)
};
duration = bench_clock::now() - begin;
return result;
}
据我所知,这完美地转发了调用中 returned 的值。
我更愿意按照惯例 return 持续时间,例如,通过使用 std::tuple
虽然我不确定如何做到完美转发 returned 值.
我的猜测是像这样使用 std::invoke_result_t
:
using bench_clock = std::conditional_t<
std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock, std::chrono::steady_clock>;
auto benchmark(auto&& func, auto&&... args)
{
auto begin{ bench_clock::now() };
decltype(auto) result{
std::invoke(
std::forward<decltype(func)>(func),
std::forward<decltype(args)>(args)...)
};
auto duration{ bench_clock::now() - begin };
return std::tuple<std::invoke_result_t<decltype(func), decltype(args)...>, bench_clock::duration>{std::forward<decltype(result)>(result), duration};
//------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ is this needed?
}
我不确定这种方法是否正确完美转发。我也不知道是否需要在 std::tuple
构造函数中使用 std::forward
。
还有一个问题,如果可调用returns void
,元组不能使用,因为std::tuple<void>
不能实例化。
我不确定如何解决这个问题。
是的,你是对的。在 benchmark
函数中调用函数 func
时,需要处理 void
return 的情况。
由于您使用了 std::invoke_result_t
和 std::conditional_t
,我假设您可以访问 c++17. Then this can be easily solved by an if constexpr
检查。
#include <iostream>
#include <chrono>
#include <tuple>
#include <type_traits> // std::is_same_v, std::invoke_result_t
#include <functional> // std::invoke
#include <utility> // std::forward, std::move
using namespace std::chrono;
using bench_clock = std::conditional_t<
high_resolution_clock::is_steady, high_resolution_clock, steady_clock>;
template<typename Func, typename... Args>
decltype(auto) benchmark(Func&& func, Args&&... args)
{
auto begin{ bench_clock::now() };
if constexpr (std::is_same_v<void, std::invoke_result_t<Func, Args...>>)
{
// can not have void result: therefore just invoke the func!
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
return bench_clock::now() - begin; // only the time duration will be returned!
}
else
{
// all other cases return the tuple of result-duration!
decltype(auto) result{ std::invoke(std::forward<Func>(func), std::forward<Args>(args)...) };
const auto duration{ bench_clock::now() - begin };
return std::make_tuple(std::move(result), duration);
}
}