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

Why is one compiler trying to use a deleted copy constructor when a type appropriate constructor is available

我有一个模板 class 属性,它包含其他类型:

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 版本。因为存在解决方法,所以我更多地寻找 "why" 这种情况,而不是其他任何事情。

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

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

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

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