给定不可复制的任务类和下面的示例代码。
#include <functional>
#include <iostream>
#include <string>
class Task
{
public:
Task()
{
}
Task(const Task& other) = delete;
Task& operator=(const Task& other) = delete;
Task(Task&& other) = default;
Task& operator=(Task&& other) = default;
void operator()() const
{
std::cout << "Task !" << std::endl;
}
};
int main()
{
auto task = Task();
auto lambda = [task = std::move(task)]
{
task();
};
std::function<void()> test = std::move(lambda);
test();
}
如果我宣布 检验 类型的变量 自动 而不是 程式我的程序在编译后能完美地运行,否则就会出现这个错误而拒绝编译。
functional:1878:34: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)'
__dest._M_access<_Functor*>() =
^
31:42: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed:
31:42: error: use of deleted function 'Task::Task(const Task&)'
13:5: note: declared here
我真的需要声明测试的类型 因为它最终会成为另一个类的成员.
我该怎么做呢?
我认为std::function应该以某种方式声明为可突变的,这样做对吗?
你可以使用 decltype(foo)
作为一个类型,当你想引用类型的 foo
. 所以,你可以这样做。
decltype(lambda) test = std::move(lambda);
但是,你的目标是把它作为一个类成员来使用 在这种情况下,你需要一些东西来 "偷 "类型。 请注意,编译器没有义务(据我所知)统一两个相同的lambda表达式的类型。 这意味着类型和lambda创建必须从同一个lambda表达式中获取。
如果你真的想用lambdas来做这件事的话 和 你可以使用C++14(用于推导返回类型),然后你可以做这样的事情。
auto make_task_runner(Task task) {
return [task = std::move(task)]() { task(); };
}
这给了我们一个函数,我们既可以用来创建lambdas,也可以用来偷取类型(通过使用 decltype()
函数的调用)。)
然后,在你的类中,你可以有。
class SomeClass {
// Type alias just to make things simpler.
using task_runner_t = decltype(make_task_runner(std::declval<Task>()));
task_runner_t task_runner;
}
然后你就可以通过使用函数的 make_task_runner
函数。
task_runner = make_task_runner(std::move(some_task));
然而,在这一点上,你已经失去了lambdas的主要好处: 能够在运行中创建一个新的短命的,未命名的函数。 现在我们有了一个命名的函数来创建lambda对象,并且我们已经给lambda类型起了一个名字(task_runner_t
),那么使用lambda来解决这个问题还有什么意义呢?
在这种特殊情况下,一个自定义的漏斗(如在 保罗的回答)就更有意义了。
... 但是 Task
已经是一个漏斗 所以你已经有了你需要的类型。Task
! 就用它,而不是发明一个包装器,这样做没有明显的好处。
一种方法是放弃lambda提供的语法糖,自己用一个漏斗来代替,例如
#include <functional>
#include <iostream>
#include <string>
class Task
{
public:
Task()
{
}
Task(const Task& other) = delete;
Task& operator=(const Task& other) = delete;
Task(Task&& other) = default;
Task& operator=(Task&& other) = default;
void operator()() const
{
std::cout << "Task !" << std::endl;
}
};
class pseudo_lambda
{
public:
pseudo_lambda (Task &&task) { m_task = std::move (task); } // <- capture
void operator()() const { m_task (); } // <- invoke
private:
Task m_task; // <- captured variable(s)
};
int main()
{
auto task = Task();
pseudo_lambda pl { std::move (task) };
pl ();
}