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

automatic decay of lambda to function pointer when passing to template function

本文关键字:函数 衰减 lambda 指针      更新时间:2023-10-16

是否有一种方法可以使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 具有任何签名衰减,所以我又回到了起点。

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

这可以工作,因为一元加号可以应用于指针,并将触发隐式转换为函数指针。

为什么要不必要地约束自己使用没有默认参数的函数指针和没有捕获的lambda,完全排除大量的函子(例如std::function, std::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...
}

作为一个TL;实现@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;
}

试着在回调定义中删除+,一切都停止工作。