3

从代码项目中获得了这个 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
4

2 回答 2

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)) { }]

编辑。

当我们使用copy-initialization类类型的变量时,仅使用标准和省略号隐式转换。从 lambda 到函数指针或从函数指针到std::functionisuser-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 成为一个可行的函数,每个参数都应该存在一个隐式转换序列(13.3.3.1),该序列将该参数转换为 F 的相应参数。

n3337 13.3.3.1/4

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

于 2012-09-18T07:17:14.290 回答
1

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

编辑:ForEver 指出的错误术语,实际上ScopeExit(func_t&& f) : func(f) {}- 不是移动构造函数。但这就是在第二种情况下被调用的原因,这就是它起作用的原因,而 copy-ctor 的隐私是第一种情况不起作用的原因。

于 2012-09-18T07:28:06.397 回答