【问题标题】:Function template works with local lambdas, but not with other functions函数模板适用于本地 lambda,但不适用于其他函数
【发布时间】:2016-05-07 16:36:04
【问题描述】:

所以我写了一个函数来“顺序地”组成 void lambdas,这样我就可以在算法中一次使用它们:

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...); };
}

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

#include <iostream>

namespace foo {
    void a() { std::cout << "a\n"; }
    void b() { std::cout << "b\n"; }
}

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...); };
                                              ~~~~~~~~~~^~~~~~~

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

【问题讨论】:

标签: c++ templates lambda c++14


【解决方案1】:

你需要反转你的函数:

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...), ...);
    };
}

这完全可以理解!

【讨论】:

  • “照原样,在递归案例中查找不会找到您的基本案例 - 它总是会调用自己。” Citation needed.
  • @n.m.尝试问题中的新示例。
  • 谢谢,我没有考虑命名空间...你能解释一下 (void)int[]{0,(void(fs(args...)),0 是什么吗)... 在这里做吗?这是一种常见的模式吗?
  • @lemko 解决了扩展包表达式的难度,使它们从左到右执行。在这里,我们创建了一个整数数组(全为 0),然后将其丢弃,并作为副作用展开一组表达式并以保证的顺序运行它们。
  • @Lemko 看看this answer。这可能是最好的解释。
猜你喜欢
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多