将lambda注入模板方法的参数

时间:2018-01-31 11:25:23

标签: c++ templates lambda sfinae

我正在尝试实现与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) >)。

2 个答案:

答案 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; } 。您也可以使用它来提取参数类型。

相关问题