为什么一个编译器在类型适当的构造函数可用时尝试使用已删除的复制构造函数?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (86)

我有一个模板类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版本。因为解决方法存在,我正在寻找更多的“为什么”这种情况比其他任何事情都要发生。

提问于
用户回答回答于

我相信这里发生的事情是保证复制省略工作(这是一个C ++ 17的功能)。一个成员声明就像

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

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

铿锵快速测试在这里 ; 如果你将语言标准切换到c ++ 17,你会看到它突然工作......

扫码关注云+社区

领取腾讯云代金券