alf*_*lfC 4 c++ rvalue user-defined-types assignment-operator
使用 C++ 多年后,我意识到使用自定义类时语法中的一个怪癖。尽管是正确的语言行为,但它允许创建非常具有误导性的界面。
这里的例子:
class complex_arg {
double r_;
double phi_;
public:
std::complex<double> value() const {return r_*exp(phi_*std::complex<double>{0, 1});}
};
int main() {
complex_arg ca;
ca.value() = std::complex<double>(1000., 0.); // accepted by the compiler !?
assert( ca.value() != std::complex<double>(1000., 0.) ); // what !?
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/Y5Pcjsc8d
可以对类定义做什么来防止这种行为? (或者至少标记类的用户第三行并没有真正执行任何分配。)
我只看到一种出路,但它需要修改类,并且它不能很好地扩展(对于可以移动的大型类)。
const std::complex<double> value() const;
Run Code Online (Sandbox Code Playgroud)
我也尝试过[[nodiscard]] value(),但没有帮助。
作为最后的手段,也许可以对返回的类型做一些事情std::complex<double>?(也就是说,假设一个人控制着该班级)
请注意,我知道有时可能需要(优化)分配给新获得的值并将其传递给另一个函数f( ca.value() = bla )。我并不是质疑这种用法本身(尽管它也很令人困惑);我的问题主要是ca.value() = bla;作为一个独立的声明,它并不像它看起来的那样。
通常,我们可以调用对象的成员函数,无论该对象的值类别是左值还是右值。
可以对类定义做什么来防止这种行为?
在现代 C++ 之前,没有办法阻止这种用法。但从 C++11 开始,我们可以引用限定成员函数来执行您要求的操作,如下所示。
从成员函数:
在重载决策期间,具有类的 cv 限定符序列的非静态成员函数
X将按如下方式处理:
无引用限定符:隐式对象参数具有对 cv 限定的左值引用类型
X,并且还允许绑定右值隐式对象参数左值引用限定符:隐式对象参数具有对 cv 限定的左值引用类型
X右值引用限定符:隐式对象参数具有对 cv 限定的 X 的右值引用类型
这使我们能够满足您对自定义托管类的要求。特别是,我们可以&限定复制赋值运算符。
struct C
{
C(int)
{
std::cout<<"converting ctor called"<<std::endl;
}
C(){
std::cout<<"default ctor called"<<std::endl;
}
C(const C&)
{
std::cout<<"copy ctor called"<<std::endl;
}
//-------------------------v------>added this ref-qualifier
C& operator=(const C&) &
{
std::cout<<"copy assignment operator called"<<std::endl;;
return *this;
}
};
C func()
{
C temp;
return temp;
}
int main()
{
//---------v---------> won't work because assignment operator is & qualified
func() = 4;
}
Run Code Online (Sandbox Code Playgroud)