ジェネリック ラムダは本体を 1 つしか持てないため、ここでは SFINAE はあまり役に立ちません。
1 つの解決策は、結果を格納できるクラスに呼び出しをパッケージ化し、void
戻り値の型に特化しvoid
て、ラムダから特別な処理をカプセル化することです。スレッド ライブラリ機能を使用すると、オーバーヘッドがほとんどなく、これを行うことができます。
auto gL =
[](auto&& func, auto&&... params)
{
// start a timer
using Ret = decltype(std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...));
std::packaged_task<Ret()> task{[&]{
return std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...); }};
auto fut = task.get_future();
task();
// stop timer and print elapsed time
return fut.get();
};
packaged_task
とのオーバーヘッドを避けたい場合はfuture
、独自のバージョンを簡単に作成できます。
template<class T>
struct Result
{
template<class F, class... A> Result(F&& f, A&&... args)
: t{std::forward<F>(f)(std::forward<A>(args)...)} {}
T t;
T&& get() { return std::move(t); }
};
template<>
struct Result<void>
{
template<class F, class... A> Result(F&& f, A&&... args)
{ std::forward<F>(f)(std::forward<A>(args)...); }
void get() {}
};
auto gL =
[](auto&& func, auto&&... params)
{
// start a timer
using Ret = decltype(std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...));
Result<Ret> k{std::forward<decltype(func)>(func),
std::forward<decltype(params)>(params)...};
// stop timer and print elapsed time
return k.get();
};