【问题标题】:Why is one compiler trying to use a deleted copy constructor when a type appropriate constructor is available当类型适当的构造函数可用时,为什么一个编译器会尝试使用已删除的复制构造函数
【发布时间】:2018-09-11 22:35:51
【问题描述】:

我有一个包含其他类型的模板类属性:

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 属性,然后使用已删除的复制构造函数,而不是简单地使用类型适当的构造函数。

这是 GCC 过于谨慎的例子吗?

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

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

或者是 MSVC 玩得又快又松,做一些标准规定不应该或不必做的事情?

很遗憾,我无法更新我的 GCC 版本。因为存在解决方法,所以我更多地寻找“为什么”会发生这种情况。

【问题讨论】:

  • GCC 4.9.4 - 非常过时。
  • @NeilButterworth,正如我在问题中所说,我正在使用专有目标并且无法更改我的 gcc 版本。

标签: c++ templates gcc4


【解决方案1】:

我相信这里发生的事情是 guaranteed copy elision 在工作(这是 C++17 的一个特性)。像

这样的成员声明
struct A
{
    Property<int> prop = 5;
};

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

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

【讨论】:

  • 谢谢!添加移动构造函数完全解决了这个问题,同时仍然通过删除复制/赋值运算符为我提供了安全保证。
猜你喜欢
  • 2023-03-21
  • 2017-07-20
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 1970-01-01
  • 2020-10-03
  • 2016-06-05
相关资源
最近更新 更多