当类型合适的构造函数可用时,为什么一个编译器试图使用已删除的副本构造函数

时间:2018-09-11 22:35:51

标签: c++ templates gcc4

我有一个模板类Property,它包装了其他类型:

template <typename T>
class Property
{
private:
    T value;
public:
    Property() = default;

    Property(const T& initialValue)
    : value(initialValue) {}
    virtual ~Property() = default;

    //Make this class non-copyable.
    Property(const Property&) = delete;
    Property& operator=(const Property&) = delete;

    virtual Property& operator=(const T& other)
    {
        value = other;
        return *this;
    }

    //... a bunch of other unimportant stuff
}

Visual Studio 15.7.6和其他一些编译器非常满意

{ //function or class definition (default member initialization)    
    Property<int> prop = 5;
}

但是,(对于专有编译目标进行了稍微修改)GCC 4.9.4在上述声明中失败了:

Error GD4849D22 use of deleted function 
'Property<T>::Property(const Property<T>&) [with T = int]' 

看来编译器正在尝试构造RValue属性,然后使用已删除的副本构造函数,而不是简单地使用类型适当的构造函数。

这是海湾合作委员会过度谨慎的案例吗?

Property<int> prop(5); //explicit constructor call - valid with GCC Compiler

Property<int> myOtherProp;
myOtherProp = 5; //Also fine (obviously)

或者是MSVC快速松散地播放并执行标准规定的不应或不必要做的事情吗?

很遗憾,我无法更新我的GCC版本。因为存在解决方法,所以我比其他任何事情都更希望这种“为什么”发生。

1 个答案:

答案 0 :(得分:2)

我相信这里发生的是guaranteed copy elision在工作(这是C ++ 17的功能)。成员声明,​​例如

struct A
{
    Property<int> prop = 5;
};

表示该成员将通过 copy-initialization 进行初始化。首先,使用转换构造函数,将从Property构造一个临时5对象,然后从中构造实际属性。由于Property是不可移动的,因此将调用复制构造函数,并将其删除。尽管甚至在C ++ 17之前,编译器就被允许elide this copy(并且从根本上来说,任何合理的编译器都将这样做),但仍然需要强制执行所有约束,例如任何必要构造函数的存在和可访问性,就好像复制完成。 C ++ 17基本上通过强制执行复制省略来消除所有这些情况。

使用c here进行快速测试;如果将语言标准切换为c ++ 17,您会发现它突然起作用了……