如何在模板函数中以lambda作为参数推断函数类型参数

How to infer a function type parameter in a template function with a lambda passed as argument?

本文关键字:函数 参数 类型参数 lambda      更新时间:2023-10-16

考虑以下内容:

#include <utility>
#include <string>
template<typename>
class C;
template<typename R, typename T>
class C<R(&)(T)> {
public:
    template<typename F>
    C(F&& fun) {}
};
template<typename T>
C<T> makeC(T&& fun) {
    return C<T>(std::forward<T>(fun));
}
int foo(int a){return a;}
int main() {
    auto p1 = makeC(foo); // OK
    auto p2 = C<int(&)(int)>([](int a){return a;});   // OK
    // auto p3 = makeC([](int a){return a;}); // FAIL
}

实例示例

p3的声明失败,因为编译器无法从通过参数传递的lambda中推断int(&)(int)的类型。p1是可以的,因为可以从函数foo轻松地推断该类型,并且p2是可以的,因为该类型已明确声明。

它失败了:

error: invalid use of incomplete type 'class C<main()::<lambda(int)> >'

有什么方法可以使编译器纠正地推断函数类型,给定lambda?

P.S。:C 17答案也可以,如果适用。

实际问题是lambda函数具有自己的类型,不能简化为 R(&)(T)。因此,C<T>是编译器正确概述的不完整类型。


只要您使用非捕捉lambdas,就可以依靠它们衰减来发挥指针并执行此操作的事实:

auto p3 = makeC(*(+[](int a){return a;}));

或以下:

template<typename T>
auto makeC(T&& fun) -> C<decltype(*(+std::forward<T>(fun)))> {
    return C<decltype(*(+std::forward<T>(fun)))>(std::forward<T>(fun));
}

与捕获Lambdas一起使用的另一个可能的解决方案是:

#include <utility>
#include <string>
template<typename T>
class C: T {
    template<typename F>
    C(F&& fun): T{std::forward<F>(fun)} {}
};
template<typename R, typename T>
class C<R(&)(T)> {
public:
    template<typename F>
    C(F&& fun) {}
};
template<typename T>
C<T> makeC(T&& fun) {
    return C<T>(std::forward<T>(fun));
}
int foo(int a){return a;}
int main() {
    auto p1 = makeC(foo);
    auto p2 = C<int(&)(int)>([](int a){return a;});
    auto p3 = makeC([](int a){return a;});
}

这样,在处理lambda时,C实际上从中继承了operator()