我有一个模板类 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 属性,然后使用已删除的复制构造函数,而不是简单地使用类型适当的构造函数。
这是 GCC 过度谨慎的情况吗?
Property<int> prop(5); //explicit constructor call - valid with GCC Compiler
Property<int> myOtherProp;
myOtherProp = 5; //Also fine (obviously)
或者这是 MSVC 快速而松散地做一些标准规定它不应该或不必做的事情的情况?
不幸的是,我无法更新我的 GCC 版本。因为存在解决方法,所以我更多地寻找发生这种情况的“原因”。
最佳答案
我相信这里发生的是 guaranteed copy elision在工作中(这是 C++17 的特性)。像这样的成员声明
struct A
{
Property<int> prop = 5;
};
表示成员将通过复制初始化 进行初始化。使用您的转换构造函数,首先,将从 5
构造一个临时 Property
对象,然后从中构造实际属性。由于 Property
不可移动,因此调用了复制构造函数,它被删除了。虽然允许编译器 elide this copy甚至在 C++17 之前(以及任何合理的编译器,因为基本上永远都会这样做),仍然需要强制执行所有约束,例如任何必要构造函数的存在和可访问性,就好像复制了一样。 C++17 通过基本上强制复制省略来消除所有这些。
使用 clang 进行快速测试 here ;如果你将语言标准切换到 c++17,你会发现它突然起作用了……
关于c++ - 为什么一个编译器在类型合适的构造函数可用时尝试使用已删除的复制构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52285048/