将lambda注入模板方法的参数

dru*_*rus 2 c++ lambda templates 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
Run Code Online (Sandbox Code Playgroud)

问题是这个主题的延续.实施

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();
}
Run Code Online (Sandbox Code Playgroud)

如果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;
}
Run Code Online (Sandbox Code Playgroud)

但是如果lambda有参数,则std::result_of_t< Function() >需要传递参数列表以推导出lambda的结果类型(例如std::result_of_t< Function(int) >).

Jiv*_*son 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;
}
Run Code Online (Sandbox Code Playgroud)

或者,更好的是,只需使用std::invoke().

  • 几乎.你应该返回`decltype(auto)`,因为如果没有它,你就不会在`func`的情况下返回引用.另外,有些人也喜欢转发`func`,因为调用操作符也可以有ref限定符,但这种情况非常罕见,所以你真的不需要.(另外:模板隐式"内联") (2认同)