通过ctor rvalue参数进行Lambda赋值

时间:2012-09-18 06:59:18

标签: c++ gcc c++11

将此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

2 个答案:

答案 0 :(得分:3)

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

n3337 12.8 / 9

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

时默认为

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

- X没有用户声明的复制赋值运算符

- X没有用户声明的移动赋值运算符

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

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

不知道为什么第一种情况不起作用,但这种情况正常

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

修改

当我们使用class-type变量的copy-initialization时,只使用标准和elipsis隐式转换。从lambda转换为函数指针或从函数指针转换为std::functionuser-defined conversion并且未使用。

n3337 8.5 / 16

初始化器的语义如下。目标类型是对象或引用的类型 初始化,源类型是初始化表达式的类型。如果初始化器不是单个(可能是 括号内的表达式,未定义源类型。

如果目标类型是(可能是cv限定的)类类型:

否则(即,对于剩余的复制初始化情况),用户定义的转换序列 可以从源类型转换为目标类型或(当转换函数时) (如果使用)对其派生类进行枚举,如13.3.1.4所述,最好的是 通过重载决议(13.3)选择。如果转换无法完成或模糊不清,那么 初始化是不正确的。

n3337 13.3.1.4/1

在8.5中指定的条件下,作为类类型对象的复制初始化的一部分,由用户定义    可以调用转换以将初始化表达式转换为要初始化的对象的类型。 重载决策用于选择要调用的用户定义的转换。假设“cv1 T”是 正在初始化的对象的类型,使用T类类型,候选函数选择如下:

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

  1. 在这两种情况下,参数列表都有一个参数,它是初始化表达式。 [注:这个论点 将与构造函数的第一个参数和隐式对象参数进行比较 转换函数。 - 结束说明]

n3337 13.3.2

1.从为给定上下文(13.3.1)构造的候选函数集中,有一组可行的函数 选择,通过比较参数的转换序列,从中选择最佳函数 最合适(13.3.3)。可行功能的选择考虑了参数和功能之间的关系 转换序列排名以外的参数。

第二,为了使F成为一个可行的函数,每个参数都应存在一个隐式转换。 quence(13.3.3.1)将该参数转换为F的相应参数。

n3337 13.3.3.1/4

但是,在考虑构造函数或用户定义的转换函数的参数时 当在类的第二步中复制/移动临时时,调用13.3.1.3的候选者 复制初始化,通过13.3.1.7将初始化列表作为单个参数或初始化时传递 list只有一个元素,并且转换为某个类X或引用(可能是cv-qualified)X 考虑到X的构造函数的第一个参数,或者在所有情况下由13.3.1.4,13.3.1.5或13.3.1.6考虑,仅 考虑标准转换序列和省略号转换序列。

答案 1 :(得分:1)

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

编辑:ForEver错误的术语指出,有效 - ScopeExit(func_t&& f) : func(f) {}不是移动构造函数。但这就是在第二种情况下被调用的内容,这就是它起作用的原因,而复制者的隐私就是第一种情况所不具备的原因。