我正在尝试实现与boost::static_visitor
类似的功能,让模板函数接受lambda并支持以下API:
int i1 = Apply([](int i) { return i; }); // doesn't compile
int i2 = Apply([]() { return 10; }); // ok
bool b1 = Apply([]() { return true; }); // ok
Apply([]() { return; }); // ok
问题是this topic的延续。 实施
template <typename Function, typename Return = std::result_of_t<Function()>,
typename = typename std::enable_if<!std::is_same<Return, void>::value>::type>
Return Apply(Function func)
{
std::cout << "invoked via Return(*)(...)" << std::endl;
return func();
}
template <typename Function, typename Return = std::result_of_t<Function()>,
typename = typename std::enable_if<std::is_same<Return, void>::value>::type>
void Apply(Function func)
{
std::cout << "invoked via void(*)(...)" << std::endl;
func();
}
如果lambda没有参数,工作正常
#include <functional>
#include <type_traits>
#include <iostream>
template <typename Function, typename Return = std::result_of_t<Function()>, typename = typename std::enable_if<!std::is_same<Return, void>::value>::type>
Return Apply(Function func)
{
std::cout << "invoked via Return(*)(...)" << std::endl;
return func();
}
template <typename Function, typename Return = std::result_of_t<Function()>, typename = typename std::enable_if<std::is_same<Return, void>::value>::type>
void Apply(Function func)
{
std::cout << "invoked via void(*)(...)" << std::endl;
func();
}
int main()
{
int i1 = Apply([]() { return 10; });
bool b1 = Apply([]() { return true; });
Apply([]() { return; });
std::cout << i1 << " " << b1 << std::endl;
return 0;
}
但是如果lambda有参数,std::result_of_t< Function() >
需要传递参数列表来推导lambda的结果类型(例如std::result_of_t< Function(int) >
)。
答案 0 :(得分:5)
一种尺寸适合所有人。 : - )
template <typename Function, typename... Args>
decltype(auto) Apply(Function&& func, Args&&... args) {
std::cout << "invoked" << std::endl;
return std::forward<Function>(func)(std::forward<Args>(args)...);
}
int main()
{
int i1 = Apply([]() { return 10; });
bool b1 = Apply([]( bool b) { return !b; }, true);
Apply([]() { return; });
std::cout << i1 << " " << b1 << std::endl;
return 0;
}
或者,更好的是,只需使用std::invoke()
。
答案 1 :(得分:0)
您可以使用辅助类来获取lambda的返回类型。
template<typename T>
struct ReturnVal {};
template<typename ReturnType, typename Class, typename... Args>
struct ReturnVal<ReturnType(Class::*)(Args...)> {
using type = ReturnType;
};
template<typename ReturnType, typename Class, typename... Args>
struct ReturnVal<ReturnType(Class::*)(Args...) const> {
using type = ReturnType;
};
然后,您可以通过传递decltype
s lambda
的{{1}}来使用它。
operator()
使用这种方法,您可以将函数指针传递给template<typename Func>
void someTemplateFunction(Func func) {
using Return = typename ReturnVal<decltype(&Func::operator())>::type;
}
。您也可以使用它来提取参数类型。