我有一个模板类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版本。因为存在解决方法,所以我比其他任何事情都更希望这种“为什么”发生。
答案 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,您会发现它突然起作用了……