【问题标题】:Overloading function when passing lambda as parameter将 lambda 作为参数传递时的重载函数
【发布时间】:2018-01-24 14:33:23
【问题描述】:

我正在尝试在返回参数为 void 或 T 时实现模板函数。我使用 sfinae 尝试了上述代码的不同变体,但仍然不确定如果 lamdba 是函数参数,这通常是否可行。 以下代码无法编译:

#include <functional>

template <typename T>
T Apply(const std::function<T()>& func)
{
    return func();
}

template <>
void Apply(const std::function<void()>& func)
{
    func();
}

int main(int argc, char *argv[])
{
    int i1 = Apply([]() { return 10; });
    bool b1 = Apply([]() { return true; });
    Apply([]() { return; });

    return 0;
}

错误:

error C2672: 'Apply': no matching overloaded function found
error C2784: 'T Apply(const std::function<T(void)> &)': could not deduce     template argument for 'const std::function<T(void)> &' from 'main::<lambda_536cc9cae26ef6d0d1fbeb7b66a2e26b>'

wandbox live

【问题讨论】:

    标签: c++ templates lambda sfinae


    【解决方案1】:

    很遗憾,您不能这样做,因为在 template argument deduction 中没有考虑隐式转换(从 lambda 闭包类型到 std::function);代码失败,因为无法推断出T

    可以直接使用lambda闭包类型作为参数类型,并将返回类型声明为auto自动推导。例如

    template <typename T>
    auto Apply(T func)
    {
        return func();
    }
    

    LIVE

    【讨论】:

    • C++98 写得太多让我不敢在适当的时候使用auto :/ +1
    • @YSC 这确实是 C++11/C++14 的强大功能,我们应该尽可能多地使用它们。
    • @YSC “在适当的时候”有时不是这样……而且代码会变得混乱,因为你不知道事物是什么类型。不是我最喜欢的 C# 导入到我必须承认的语言! (在这里虽然它似乎工作!)
    • @songyuanyao 如果不清楚,这正是我的看法。
    • “模板实参推导不考虑隐式转换”这是常说的,但不太对,我觉得这句话犯了迷惑人的罪。 Derived->base、CV 和数组指针转换都是隐式的,并且都可以在调用参数被推导的函数模板时发生。
    【解决方案2】:

    这是因为template deduction 需要对每个函数参数进行完美匹配才能成功推导出模板参数。

    您需要将函数对象本身模板化:

    #include <type_traits>
    
    template <class Function, class Return = std::result_of_t<Function()>>
    Return Apply(Function func)
    {
        return func();
    }
    

    用法:

    #include <iostream>
    
    int main()
    {
        std::cout << Apply([]() { return 42; }) << "\n";
    }
    

    live demo

    【讨论】:

    • 太棒了!我稍微更新了 SFINAE:link
    • 有趣的是,如果有办法编译以下代码:int i1 = Apply([](int i) { return i; });。在这种情况下,我需要在推导 Result(= class Return = std::result_of_t)时明确地对 Function() 进行“int”。但是有没有更通用的方法来推断 lambda 参数?
    • @drus 您正在寻找的关键字是(完美)转发。这可以通过 C++17 来实现。环顾四周,进行测试,如果遇到困难,请提出一个新问题。
    猜你喜欢
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 2021-04-14
    • 2017-06-14
    • 2016-04-21
    • 2016-07-19
    相关资源
    最近更新 更多