如何确定捕获不可复制参数的 lambda 的类型?
How to determine the type of a lambda which captures a noncopyable parameter?
给定不可复制的任务类和下面的示例代码
#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();
}
如果我用 auto 类型而不是std::function 声明测试变量,程序可以完美编译并运行,否则它将拒绝编译并出现此错误:
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应该以某种方式声明为可变的是对的吗?
当您想要引用foo
的类型时,可以使用decltype(foo)
作为类型。因此,您可以这样做:
decltype(lambda) test = std::move(lambda);
但是,您声明的目标是将其用作类成员。 在这种情况下,您需要一些东西来"窃取"类型。 请注意,编译器没有义务(据我所知(统一两个相同的 lambda 表达式的类型。 这意味着类型和 lambda 创建都必须取自同一个 lambda 表达式。
如果您真的想使用 lambda 执行此操作,并且可以访问 C++14(对于推导的返回类型(,那么您可以执行以下操作:
auto make_task_runner(Task task) {
return [task = std::move(task)]() { task(); };
}
这给了我们一个函数,我们既可以使用它来创建 lambda,也可以使用它来窃取类型(通过在函数的调用中使用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));
但是,在这一点上,您已经失去了 lambda 的主要优势:能够即时创建新的短期未命名函数。 现在我们有一个命名函数来创建 lambda 对象,并且我们已经给 lambda 类型起了一个名字 (task_runner_t
(,那么使用 lambda 来解决这个问题有什么意义呢?
在这种特殊情况下,自定义函子(如 Paul 的答案(更有意义。
。但是,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 ();
}
现场演示
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 在 lambda 捕获中声明的变量的类型推导
- C++ 模板类型的静态 lambda 成员的构造
- Clang 工具,用于提取给定 lambda 类型的 lambda 主体
- 如果 lambda 没有指定的类型,std::function 如何接受 lambda?
- Lambda可以用作非类型模板参数吗
- 如何确定捕获不可复制参数的 lambda 的类型?
- 如何制作可以接受任何类型的参数的 std::函数和 lambda
- C++模板函数中,指定回调函子/lambda 的参数类型,同时仍允许内联?
- 运算符中的不同类型? 具有无捕获,相同的签名,lambda
- 通过参数传递 lambda(无函数类型模板)
- 有没有办法根据 lambda 参数返回类型部分专用化我的模板化函数?
- C++ 中的 Java8 lambda 类型比较
- 推断衰减到函数指针的 lambda 类型
- 从 lambda 内部返回 C++11 中的 lambda 类型(平面映射函数)
- 如何强制编译器识别模板化函数中的lambda类型
- 初始化和 lambda 类型参数
- 具有相同签名和捕获的常见 lambda 类型
- 我可以在std::函数中使用模板类型T来传递lambda类型的函数C++11吗
- C++ upper_bound 对 <lambda 类型的对象没有匹配的函数调用