我有这样的功能:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
// data loading stuff
callback(body, subject, header);
}
Run Code Online (Sandbox Code Playgroud)
问题是我并不需要使用subject,并header在我的回调函数.现在我正在以这种方式处理它:
loadData([](std::string body, std::string, std::string){
std::cout << body;
})
Run Code Online (Sandbox Code Playgroud)
我想用它替换它
loadData([](std::string body){
std::cout << body;
})
Run Code Online (Sandbox Code Playgroud)
并自动传递给回调函数尽可能多的参数.我不想loadData为所有3个可能的参数计数手动重载函数.我也不想在调用站点上使用任何更复杂的lambda语法,因为我的库应该清楚,供其他人使用.这可能使用C++ STL和Boost吗?
考虑这个伪代码段:
class SomeClass
{
public:
SomeClass()
{
if(true)
{
fooCall = [](auto a){ cout << a.sayHello(); };
}
else
{
fooCall = [](auto b){ cout << b.sayHello(); };
}
}
private:
template<typename T>
std::function<void(T)> fooCall;
};
Run Code Online (Sandbox Code Playgroud)
我想要的是一个fooCall存储泛型lambda 的类成员,而lambda又在构造函数中赋值.
编译器抱怨fooCall不能是模板化的数据成员.
关于如何在类中存储泛型lambda,有没有简单的解决方案?
事实证明,以下定义对我非常有用:
template<class Func, class... Args>
void apply_on_each_args(Func f, Args... args)
{
(f(args), ...);
}
Run Code Online (Sandbox Code Playgroud)
基本上,在逗号运算符上折叠的参数包允许定义对带参数的函数的多个调用.例如:
apply_on_each_args([] (auto x) { cout << x << endl; }, 1, 2, "hello");
Run Code Online (Sandbox Code Playgroud)
将打电话给匿名lambda 1,2和"hello".
提出这个想法,我想做同样的事情,但传递lambdas采取两个,三个等参数.例如,类似的东西
apply_on_each_args([] (auto x, auto y) { /* use x and y */ }, 1, 2, "hello", "bye");
Run Code Online (Sandbox Code Playgroud)
任何能够实现它的线索,技术,想法等?
template-meta-programming variadic-templates generic-lambda fold-expression c++17
C++ 标准专家的几个相关问题。
传入的 C++20引入了模板 lambdas ( P0428R2 )。
所以代替
auto x = [](auto x, auto y){ return x+y; };
Run Code Online (Sandbox Code Playgroud)
我们可以指定模板参数如下
auto x = []<typename T>(T x, T y){ return x+y; };
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好。
第一个问题:模板 lambda 中的显式模板参数是否只能从参数中推导出来,或者是否可以添加非推导出的模板参数?
阅读 P0428r1 我没有看到任何明确的限制,但是,我也没有看到非推导模板参数的例子。
在第一个近似值中,我认为非推导的模板参数是合法的,因为我看到以下愚蠢的代码
int main()
{
[]<int = 0>(){ }();
}
Run Code Online (Sandbox Code Playgroud)
使用 g++(10.0.0 head)和 clang++(10.0.0 head)编译和运行。
假设允许非推导的模板参数,第二个问题是:如何在提供模板参数的同时调用模板 lambda?
举例:给定以下模板 lambda
auto x = []<std::size_t I>(auto t){ return std::get<I>(t); };
Run Code Online (Sandbox Code Playgroud)
I在没有显式命名的情况下调用此类 lambda 时,是否有一些语法用于指定模板参数operator()?
我试过
x<0u>(y);
Run Code Online (Sandbox Code Playgroud)
但 …
当我将lambda分配给显式类型变量时(例如,当它是递归的时,为了捕获函数本身),我使用std::function.
以这个愚蠢的"位计数"函数为例:
std::function<int(int)> f;
f = [&f](int x){ return x ? f(x/2)+1 : 0; };
Run Code Online (Sandbox Code Playgroud)
当我们使用auto参数进行泛化时x,如C++ 14泛型lambda中所介绍的情况怎么样?
std::function<int(???)> f;
f = [&f](auto x){ return x ? f(x/2)+1 : 0; };
Run Code Online (Sandbox Code Playgroud)
很显然,我不能把auto在function类型参数.
是否有可能通常定义一个仿函数类来覆盖上面的确切情况,但仍然使用lambda作为函数定义?
(不要过度概括这一点,只接受一个自动参数并对返回值进行硬编码.)用例适用于上述场景:通过引用为递归调用捕获函数本身.
给出以下可变参数模板:
template<typename... Params>
void fun(void(*f)(Params...), Params... params) {
f(params...);
}
int main() {
fun(+[](int a, int b) {}, 2, 3);
}
Run Code Online (Sandbox Code Playgroud)
现在,当fun使用lambda 调用时,我需要明确指定所有lambda参数的类型.这似乎是多余的,因为int, int可以从中推断出来2, 3.有没有办法让它更简洁自动?
我想以下工作,但它没有:
template<typename... Params>
void fun(void(*f)(Params...), Params... params) {
f(params...);
}
int main() {
fun(+[](auto a, auto b) {}, 2, 3);
}
Run Code Online (Sandbox Code Playgroud)
我正在编译g++ 5.4.0和-std=c++14.
考虑以下代码
#include <iostream>
#include <functional>
namespace A {
template<typename T>
struct X {
using Function = std::function<int(T)>;
static Function f;
};
template<typename T>
typename X<T>::Function X<T>::f = [](auto) { return 42; };
}
int main() {
std::cout << A::X<int>::f(0);
}
Run Code Online (Sandbox Code Playgroud)
GCC和clang都接受此代码,但MSVC(测试版本19.00.23506)给出:
error C2888: 'auto <lambda_ce48e25aa4b9e3d225584044e4eae9e2>::operator ()(_T1) const': symbol cannot be defined within namespace 'A'
实际上,如果我删除命名空间A并在全局命名空间中定义所有内容,则接受代码.如果我使lambda表达式非泛型,则相同.
有人可以解释一下MSVC在这段代码中看到的问题是什么吗?C++ Standard是否限制在上面的上下文中使用泛型lambda?
当泛型 lambda 被存储为 a 时std::function,我们需要提供一个具体的类型,比如,
std::function<double(double)>
Run Code Online (Sandbox Code Playgroud)
因此绑定到特定类型,
以下声明:
std::function<auto(auto)>
Run Code Online (Sandbox Code Playgroud)
引发编译器错误。
我知道,从 c++14 开始,auto可用于存储 lambda 的返回值,但是在将 lambda 存储在std::function.
我想写一个通用的lambda作为变体的访客。此变体的成员包含constexpr成员值,我想在访问者中使用它。例如:
#include <variant>
template<int r>
struct S {
constexpr static int this_r = r;
};
int f(std::variant<S<0>, S<1>, S<2> > v) {
return std::visit([](auto const& arg) {
if constexpr(arg.this_r == 0) { return 42; }
else { return arg.this_r; }
}, v);
}
int g() {
std::variant<S<0>, S<1>, S<2> > x = S<2>();
return f(x);
}
Run Code Online (Sandbox Code Playgroud)
GCC很高兴从7.1版本开始编译此代码。另一方面,Clang抱怨the的arg.this_r == 0参数if constexpr不是常量,可以回溯到4.0.0版本,但是在当前trunk中仍然存在。
谁在这里,我该如何避免这个问题(假设一个简单的对象if不会被剪裁,因为两个分支之一都无法实例化)?
附录:argClang作为值而不是const左值引用传递,很高兴,但是不幸的是,这不是我的选择。
最近,我阅读了Barry对这个问题Recursive lambda functions in C++11的回答:
template <class F>
struct y_combinator {
F f; // the lambda will be stored here
// a forwarding operator():
template <class... Args>
decltype(auto) operator()(Args&&... args) const {
// we pass ourselves to f, then the arguments.
// [edit: Barry] pass in std::ref(*this) instead of *this
return f(std::ref(*this), std::forward<Args>(args)...);
}
};
// deduction guide
template <class F> y_combinator(F) -> y_combinator<F>;
Run Code Online (Sandbox Code Playgroud)
基本上,y_combinator允许更轻松地编写递归 lambda 表达式(例如,无需 delcare a std::function)。当我玩的时候y_combinator,我发现了一些奇怪的东西: …
generic-lambda ×10
c++ ×8
c++14 ×5
lambda ×5
c++17 ×3
std-function ×2
auto ×1
c++11 ×1
c++20 ×1
namespaces ×1
template-argument-deduction ×1
templates ×1
variant ×1