传递给模板函数时,lambda自动衰减到函数指针

Posted

技术标签:

【中文标题】传递给模板函数时,lambda自动衰减到函数指针【英文标题】:automatic decay of lambda to function pointer when passing to template function 【发布时间】:2014-04-13 11:30:19 【问题描述】:

有没有办法让 lambda 衰减到指针,而无需显式转换为正确的签名?这会整理一些代码:

template<typename T> T call(T(*func)()) return func(); 
int ptr() return 0; 
int main()
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([] return 0; ));
    auto ret3 = call([] return 0; );  //won't compile

很明显,只有当 lambda 衰减为指针时,对 call 的调用才有效,但我猜这只有在选择了正确的函数重载/模板后才会发生。不幸的是,我只能想到涉及模板​​的解决方案,以使具有任何签名的 lambda 衰减,所以我回到了第一方。

【问题讨论】:

【参考方案1】:

您可以更改 lambda 以使用一元 + 运算符:+[] return 0;

这是因为一元加号可以应用于指针,并且会触发到函数指针的隐式转换。

【讨论】:

@LorenzoPistone 这已经作为A positive lambda: +[] - What sorcery is this?得到了很多关注 @Nikos 不是真的。那里的一元加号触发到函数指针的隐式转换,因为一元加号可以应用于函数指针。 See this 作为实际导致其工作的示例。 @Nikos 函数指针仍然是指针。您有对象指针类型、函数指针类型和指向成员类型的指针。我认为答案不需要澄清,但如果你愿意,可以编辑它。【参考方案2】:

为什么你会不必要地限制自己使用没有默认参数的函数指针和没有捕获的 lambda,完全排除大量仿函数(例如 std::functionstd::bind 的任何结果以及其他所有具有合适的 operator() )?

最好只是扩展你的函数签名:

template <typename F> 
auto call(F func) -> decltype(func())  
  return func(); 


int ptr()  return 0; 

int g(int i = 0) return i;

int main() 
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([] return 0; )); //tedious, but works
    auto ret3 = call([] return 0; );  //ok now.

    auto ret4 = call(g); //ok now!
    int i = 42;
    auto ret5 = call([=]return i;); //works, too!
    auto ret6 = call(std::bind(g, i)); //and so on...

【讨论】:

不,每天都会发生由于您正在使用的其他库而受到限制的情况。 @LorenzoPistone 抱歉,从您的问题中我不清楚 call 是第三方 API 的一部分并且无法更改。这样一来,Simple 显示的 正 lambda 就是首选武器。 仍然是一个完全合理的解决方案。在call 内部,您可以转换为函数指针类型decltype(func())(*)() @MSalters 不,他不能。首先,因为call是他无法更改的第三方API函数。其次,因为一般函子、带有默认参数的函数和带有捕获的 lambdas 不允许转换。【参考方案3】:

作为 TL;DR; @Simple 提案的实现,我写了一个简单的测试如下:

SCENARIO("decay_equiv", "")

    auto callback = +[](struct mosquitto *, void *,
                        const struct mosquitto_message *)->void;

    typedef typename std::is_same<
            typename std::decay<decltype(callback)>::type,
            typename std::decay<void (*)(struct mosquitto *, void *, const struct mosquitto_message *)>::type
                    >::type s;
    std::cout << s::value << std::endl;

尝试删除回调定义中的+,一切都会停止工作。

【讨论】:

以上是关于传递给模板函数时,lambda自动衰减到函数指针的主要内容,如果未能解决你的问题,请参考以下文章

什么是数组到指针衰减?

将 lambda 作为参数传递 - 通过引用或值?

将 lambda 传递给函数模板

C++20:非类型模板参数中的非捕获 lambda

传递给函数时找不到c ++向量?

在 gcc 上将成员函数指针传递给模板成员函数时出现问题