【问题标题】:Matching a C++ lambda expression in templates匹配模板中的 C++ lambda 表达式
【发布时间】:2016-09-27 00:36:51
【问题描述】:

我正在尝试匹配 C++ 模板中的可调用对象,并根据作为参数接收的可调用对象的类型提供不同的实现。

我有以下模板函数:

template<class Ret, class... Args>
void fun(std::function<Ret(Args...)> f) {}

template<class Ret, class... Args>
void fun(Ret(*f)(Args...)) {}

它们接受std::function 对象和普通函数指针,并正确推断出它们的返回Ret 和参数Args 类型。但是,我在传递匿名 lambda 表达式时遇到了困难,因为它们与上面的任何模板都不匹配。

调用类似的东西

fun([](int x, int y){return x + y;})

导致编译错误。实现接受匿名 lambda 函数的模板表达式的正确方法是什么?也许一种方法是检查正在传递的类是否具有operator() 方法?

【问题讨论】:

    标签: c++ templates lambda std-function


    【解决方案1】:

    转换发生在模板参数替换之后。 lambda 的类型不是std::function,而是匿名类型。实际上,您将收到一个匿名 lambda,以便接收任何可调用对象。

    您似乎关心的是限制接收到的对象以定义operator()。这个问题很容易用表达式 sfinae 解决。但是,由于您没有接收参数,因此很难检查表达式是否有效。

    这不是一个通用示例,但它适用于没有 auto 作为其参数之一的任何 lambda,或者任何没有重载 operator() 的对象:

    template<typename F>
    auto fun(F f) -> void_t<decltype(&T::operator())> {
        // ...
    }
    

    void_t 实现如下:

    template<typename...>
    using void_t = void;
    

    decltype 中的表达式必须有效才能使函数存在。

    如果您希望代码使用更多类型,则必须提供可以指定参数的重载。检查现在很容易实现:

    // Another overload of your function
    template<typename F, typename... Args>
    auto fun(F f) -> void_t<decltype(f(std::declval<Args>()...)> {
        // ...
    }
    

    这样,它也适用于泛型 lambda 和重载运算符。

    【讨论】:

    • fun 与非推导 Args... 的调用会很丑陋...并且需要将 lambda 存储在变量中以获取其类型:-/
    • 确实如此,但它可能会让 OP 了解如何限制他的功能
    【解决方案2】:

    这是有效的 C++ 代码,C++14 级别的 gcc 6.1.1 将支持我:

    template<typename F>
    void foo(F &&f)
    {
    }
    
    void bar()
    {
        auto lambda=[](auto a, auto b) {};
    
        foo(lambda);
    }
    

    如您所见,模板不可能推断出 lambda 的参数。 lambda 的参数类型在使用之前是未知的。

    正如另一个答案所示,您可以推断出某些东西有一个operator(),但这已经差不多了。

    【讨论】:

    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    相关资源
    最近更新 更多