这可能是一个概念性问题。我正在实现以lambda
为参数的函数。但是,我无法理解lambda
的确切类型。例如:
auto T = [] () { printf("hello world\n"); };
auto F = move(T);
T(); // print "hello world"
F(); // print "hello world"
我在move
上致电T
后想到T
的内容消失了。换句话说,我期望以下行为:
function<void> T = [] () { printf("hello world\n");};
auto F = move(F);
F(); // print "hello world"
T(); // throw error
回到最初的问题,将lambda
传递给function<void()>
的班级成员的最佳做法是什么?我看到了许多不同的答案,其中一些使用const function<void()>&
,另一些则建议使用模板F&&
struct Foo {
function<void()> f;
// Option 1:
void set_f(const function<void()>& in) {f=in;}
// Option 2: template
template <typename F>
void set_f(F&& in) { // what to write here??? }
}
这两个选项是否足以捕获大多数输入类型?
答案 0 :(得分:6)
您似乎对编译器对lambda表达式的作用有一个基本的误解。 Lambda表达式转换为具有唯一名称的仿函数。当你调用lambda时,你只需要调用函子的operator()
。
所以你的第一个例子中的lambda将创建类似这样的
struct __uniquely_named_lambda
{
void operator()() const
{
printf("hello world\n");
}
};
如果这个lambda存储任何状态,那么move
将移动状态,但你的lambda是无状态的,所以move
什么都不做;你不能剥离operator()
的身体并将其移到其他地方。
例如,这些语句将生成输出4 0 4
std::string s{"Test"};
auto T = [s]() { std::cout << s.size() << ' '; }; // make a copy of s
T();
auto F = std::move(T);
T();
F();
std::function
是一个容器,可以接受与指定签名匹配的任何可调用,并且您的lambda就是这样一个可调用的。当您move
std::function
时,您将其存储的可调用目标移动到目标位置。尝试调用原始目标然后抛出bad_function_call
,这与move
lambda非常不同。
我将set_f
成员函数写为
template <typename F>
void set_f(F&& in)
{
f = std::forward<F>(in);
}
您的示例中的 F
是转发引用,这意味着它可以接受调用方传递的左值或右值。然后,赋值将复制赋值或移动赋值参数。