函数模板可用于本地lambda,但不能用于其他函数

Function template works with local lambdas, but not with other functions

本文关键字:用于 但不能 其他 函数 函数模板 lambda      更新时间:2023-10-16

所以我写了一个函数,它"顺序地"组成void Lambda,这样我就可以在算法中同时使用它们:

template <typename F, typename... Fs>
auto lambdaList(F f, Fs... fs)
{
    return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
}
template <typename F>
auto lambdaList(F f)
{
    return [=] (auto&... args) { f(args...); };
}

如果我使用本地lambdas,它会起作用,但当我使用不同名称空间中的函数时就不行了:

#include <iostream>
namespace foo {
    void a() { std::cout << "an"; }
    void b() { std::cout << "bn"; }
}
template <typename F, typename... Fs>
auto lambdaList(F f, Fs... fs)
{
    return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
}
template <typename F>
auto lambdaList(F f)
{
    return [=] (auto&... args) { f(args...); };
}
int main() {
    auto printStarBefore = [] (const std::string& str) { 
        std::cout << "* " + str; 
    };
    auto printStarAfter = [] (const std::string& str) { 
        std::cout << str + " *" << std::endl; 
    };    
    lambdaList(printStarBefore, printStarAfter)("hi");  // ok
    lambdaList(foo::a, foo::b)();                       // error
}

错误为no matching function for call to 'lambdaList()',带有:

main.cpp:11:56: note:   candidate expects at least 1 argument, 0 provided
     return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
                                              ~~~~~~~~~~^~~~~~~

为什么它有时有效,有时无效?

您需要反转您的函数:

template <typename F>
auto lambdaList(F f)
{
    return [=] (auto&... args) { f(args...); };
}
template <typename F, typename... Fs>
auto lambdaList(F f, Fs... fs)
{
    return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
}

按原样,在递归情况下,您的基本情况不会通过非限定查找找到——它只能通过依赖于参数的查找找到。如果参数与lambdaList不在同一个命名空间中,则根本找不到它,递归步骤将始终调用自己。这就是你错误的根源。

新的排序允许通过正常的非限定查找来找到基本情况lambdaList()——现在它在递归lambdaList()的定义点上是可见的。


也就是说,我们可以做得更好。编写一个调用所有内容的函数:

template <typename... Fs>
auto lambdaList(Fs... fs) { 
    using swallow = int [];
    return [=](auto const&... args) {
        (void)swallow{0,
            (void(fs(args...)), 0)...
        };
    };
}

现在我们不需要担心任何类型的查找。如果你可以使用一个足够现代的编译器来支持一些C++1z功能,那么使用可以大大减少上述功能

template <typename... Fs>
auto lambdaList(Fs... fs) { 
    return [=](auto const&... args) {
        (fs(args...), ...);
    };
}

这完全可以理解!