通过ctor-rvale参数进行Lambda赋值

Lambda assignment via ctor rvalue argument

本文关键字:Lambda 赋值 ctor-rvale 参数 通过      更新时间:2023-10-16

从代码项目中获得了ScopeExit类,但它不会在GCC 4.5.3上构建。感谢您的帮助。

class ScopeExit : private boost::noncopyable
{
typedef std::function<void()> func_t;
public:
ScopeExit(func_t&& f) : func(f) {}
~ScopeExit() { func(); }
private:
// no default ctor
ScopeExit();
// Prohibit construction from lvalues.
ScopeExit(func_t&);
// Prohibit new/delete.
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void *);
void operator delete[](void *);
const func_t func;
};

ScopeExit exit = [&]() { };

gcc 4.5.3错误:

In member function ‘void test()’:
error: conversion from ‘test()::<lambda()>’ to non-scalar type ‘ScopeExit’ requested

编辑:

ScopeExit exit([&]() { }); // this works

它是复制/移动初始化。您的复制c-tor被删除,移动c-tor也被删除。

n3337 12.8/9

如果类X的定义没有显式声明移动构造函数,则会隐式声明一个当且仅当

--X没有用户声明的复制构造函数,

--X没有用户声明的副本分配运算符,

--X没有用户声明的移动分配运算符

--X没有用户声明的析构函数,并且

--move构造函数不会被隐式定义为已删除

不知道为什么第一个案例不起作用,但这个案例很好

template<typename T>
ScopeExit(T&& f) : func(std::move(f)) {}
ScopeExit(ScopeExit&& rhs) : func(std::move(rhs.func)) { }]

编辑

当我们使用类类型变量的copy-initialization时,只使用标准和省略隐式转换。从lambda到函数指针或从函数指针到std::function的转换是user-defined conversion,不使用。

n3337 8.5/16

初始化程序的语义如下。目标类型是对象或引用的类型initialized,而源类型是initializer表达式的类型。如果初始值设定项不是单个(可能带括号)表达式,则未定义源类型。

如果目的地类型是(可能是cv合格的)类类型:

否则(即,对于剩余的副本初始化情况),用户定义的转换序列可以从源类型转换为目标类型,或者(当转换函数使用)到其派生类,如13.3.1.4中所述,并且最好的是通过过载分辨率(13.3)选择。如果转换无法完成或不明确,则初始化格式不正确

n3337 13.3.1.4/1

在8.5中指定的条件下,作为类类型对象的复制初始化的一部分,用户定义可以调用转换来将初始值设定项表达式转换为正在初始化的对象的类型。重载解析用于选择要调用的用户定义转换。假设"cv1T"为被初始化对象的类型,T是类类型,候选函数的选择如下:

--T的转换构造函数(12.3.1)是候选函数。

  1. 在这两种情况下,参数列表都有一个参数,即初始值设定项表达式。[注:此论点将与构造函数的第一个参数和隐式对象参数进行比较转换函数的。--尾注]

n3337 13.3.2

1.根据为给定上下文构建的候选函数集(13.3.1),一组可行函数为选择,通过比较最佳拟合(13.3.3)。可行函数的选择考虑了自变量和函数之间的关系除了转换序列的排序之外的参数。

其次,对于F是一个可行函数,每个自变量都应该存在一个隐式转换se-将该参数转换为F.的相应参数的序列(13.3.3.1)。

n3337 13.3.3.1/4

但是,当考虑构造函数或用户定义的转换函数的参数时当在类的第二步中被调用以复制/移动临时时,由13.3.1.3指定的候选者复制初始化,当将初始值设定项列表作为单个参数传递时,或当初始值设定值设定项列表只有一个元素,转换为某个类X或引用(可能是cv限定的)X是对于X构造函数的第一个参数,或在所有情况下由13.3.1.4、13.3.1.5或13.3.1.6考虑,仅考虑了标准转换序列和省略号转换序列

通过将复制构造函数设为私有,禁止了复制初始化(这是第一种情况下发生的情况)。但是您的构造函数ScopeExit(func_t&& f) : func(f) {}是公共的,这就是第二个(工作)声明中调用的内容。玩弄两个actor的访问控制规范应该验证这一点。

编辑:正如ForEver所指出的,实际上是错误的术语——ScopeExit(func_t&& f) : func(f) {}不是一个移动构造函数。但这就是第二种情况下的名称,这就是它工作的原因,而复制ctor的隐私也是第一种情况不工作的原因。