所以我写了一个函数,它组成了“顺序”的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...); };
~~~~~~~~~~^~~~~~~
为什么它有时会起作用,但有时却不起作用?
答案 0 :(得分:6)
您需要反转您的功能:
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...), ...);
};
}
这是完全可以理解的!