struct T {
int m_x;
T(int x) : m_x(x) {}
operator T() {
return T(0);
}
};
int main() {
volatile T v(2);
T nv(1);
nv = v; // nv.m_x = 0
}
给出:
prog.cpp: In function ‘int main()’:
prog.cpp:14:10: error: no match for ‘operator=’ in ‘nv = v’
prog.cpp:14:10: note: candidates are:
prog.cpp:1:8: note: T& T::operator=(const T&)
prog.cpp:1:8: note: no known conversion for argument 1 from ‘volatile T’ to ‘const T&’
prog.cpp:1:8: note: T& T::operator=(T&&)
prog.cpp:1:8: note: no known conversion for argument 1 from ‘volatile T’ to ‘T&&’
我需要定义什么类型转换才能使其工作?
答案 0 :(得分:4)
<小时/> 通过使用特殊成员函数的显式默认版本来声明这样的转换也是不可能的(参见长答案以供参考)。
您必须提供用户定义的转化方式才能启用此类转让。你可以
示例:
X (X const volatile & xo);
X& operator= (X const volatile & xo);
<小时/>
当且仅当声明
e
格式正确时,表达式T t=e;
才能隐式转换为T类型发明了临时变量t(8.5)。
由于声明T t = e;
,在这种情况下e
的类型为volatile T
,因此要求复制初始化有效,您需要一个复制构造函数挥发性的。
我已经回答了(Why am I not provided with a default copy constructor from a volatile?)。 因此,您需要提供一种用户定义的方法,即从易失性T中复制初始化T.
X (X const volatile & xo);
注意:
这将使您的作业有效。
另一种使示例代码分配工作的方法是复制赋值运算符。
不幸的是,标准也表示编译器不会为volatile到非易失性对象的转换提供隐式复制赋值运算符。
如果类定义没有显式声明一个复制赋值运算符,则会隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认值(8.4)。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。类X的隐式声明的复制赋值运算符将具有
形式<强> X&安培; X :: operator =(const X&amp;)
如果
- X的每个直接基类B都有一个复制赋值运算符,其参数类型为const B&amp; const volatile B&amp;或B,和
- 对于类型为M(或其数组)的X的所有非静态数据成员,每个这样的类类型具有复制赋值运算符,其参数是const M&amp;,const volatile M&amp;或M. 122
否则,隐式声明的复制赋值运算符将具有
形式<强> X&安培; X ::运算符=(X&安培;)强>
隐式声明的复制赋值运算符的引用参数不能绑定到volatile lvalue;见 C.1.9 。
在other answer我引用的C.1.9中说:
隐式声明的复制构造函数和隐式声明的复制赋值运算符无法复制volatile lvalue。 [...]
结果是,如果我们想拥有一个合适的副本赋值运算符,我们必须提供。
X& operator= (X const volatile & xo);
另请注意,您无法从volatile明确默认声明赋值/构造函数。
明确默认的功能
- 是一个特殊的会员功能,
- 具有相同的声明函数类型(可能不同的ref限定符除外,在复制构造函数或复制赋值运算符的情况下,参数类型可以是“引用非const T”,其中T是成员函数的类的名称)就像它已被隐式声明一样,并且
- 没有默认参数。
以下注释已从最终的C ++ 11标准中删除,但存在于N3242草案中。它仍然存在。
[注意:这意味着参数类型,返回类型和 cv-qualifiers必须与假设的隐式声明匹配。 -end note]
由于假设的隐式声明是非易失性的,因此您无法使用默认声明。
答案 1 :(得分:1)
以下是如何获得允许使用volatile源的复制构造函数和复制赋值:
struct X {
X(const X& o) : members(o.members) {}
X(const volatile X& o) : members(o.members) {}
X& operator=(const X& o) {v=o.v; return *this;}
X& operator=(const volatile X& o) {v=o.v; return *this;}
};
请注意,这会产生一些后果。这种类型不再是POD,甚至不是可复制的。这可能会破坏使其变得不稳定的全部意义。
答案 2 :(得分:0)
您可以实现赋值运算符=
:
T& operator=(const volatile T &rhs) {
m_x = rhs.m_x;
return *this;
}