重载 operator[] 并且没有得到 "lvalue required as left operand of assignment" 错误
Overloading operator[] and NOT getting "lvalue required as left operand of assignment" error
这与所有 "lvalue required as left operand of assignment" 错误问题有点相反。
我有一个重载 operator[] 的 class,但只有 return 是一个临时版本。如果是 return 一个 int:
struct Foo
{
int operator[]( int idx ) const { return int( 0 ); }
};
Foo f;
f[1] = 5;
我理应得到左值编译器错误。但是,如果它 return 是结构类型,编译器(在本例中为 GCC 7.2)根本不会抱怨:
struct Bar {};
struct Foo
{
Bar operator[]( int idx ) const { return Bar(); }
};
Foo f;
f[1] = Bar();
如果 Bar 是临时的并且没有专门的运算符 =,为什么它不会以同样的方式抱怨?
另一个问题,有没有办法让这个抱怨?如果以这种方式使用,显然这是一个编码错误
is there some way to make this complain?
您可以将显式默认赋值运算符与 ref-qualifier:
一起使用
struct Bar {
Bar& operator=(const Bar&) & = default;
// ^
这使得右值赋值 ill-formed,而左值赋值保持 well-formed。
请注意,声明赋值运算符会禁用隐式移动赋值,因此如果需要,您可能还需要定义它(也是默认的,并且可能在适当的情况下使用右值引用限定符)。
Why wouldnt this complain in the same way if Bar is a temporary and it doesnt have an specialized operator =?
因为隐式生成的赋值运算符不是ref-qualified.
Clearly this is a coding error if it were to be used this way
右值赋值并非普遍错误。对于一些应该表现得像引用的类型,右值的赋值是很自然的。这是因为赋值修改了引用的对象,而不是临时对象本身。
一个典型的用例是分配给右值std::tie
(来自cppreference的示例):
std::set<S> set_of_s; // S is LessThanComparable
S value{42, "Test", 3.14};
std::set<S>::iterator iter;
bool inserted;
// unpacks the return value of insert into iter and inserted
std::tie(iter, inserted) = set_of_s.insert(value);
是的,如果隐式运算符被限定,并且 non-qualified 需要显式声明,考虑到引用类型是例外而不是规范,这可能会更好。但这不是语言的样子,改变它是一种向后不兼容的改变。
是的,有一种方法可以通过删除这些方法使其成为编译错误:
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
请注意,这将禁用 auto-generation 其他运算符和构造函数,因此您必须全部定义它们:
struct Bar {
Bar()=default;
Bar(const Bar&) = default;
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
Bar& operator=(const Bar&)& =default;
Bar& operator=(Bar&&)& =default;
};
这与所有 "lvalue required as left operand of assignment" 错误问题有点相反。
我有一个重载 operator[] 的 class,但只有 return 是一个临时版本。如果是 return 一个 int:
struct Foo
{
int operator[]( int idx ) const { return int( 0 ); }
};
Foo f;
f[1] = 5;
我理应得到左值编译器错误。但是,如果它 return 是结构类型,编译器(在本例中为 GCC 7.2)根本不会抱怨:
struct Bar {};
struct Foo
{
Bar operator[]( int idx ) const { return Bar(); }
};
Foo f;
f[1] = Bar();
如果 Bar 是临时的并且没有专门的运算符 =,为什么它不会以同样的方式抱怨? 另一个问题,有没有办法让这个抱怨?如果以这种方式使用,显然这是一个编码错误
is there some way to make this complain?
您可以将显式默认赋值运算符与 ref-qualifier:
一起使用struct Bar {
Bar& operator=(const Bar&) & = default;
// ^
这使得右值赋值 ill-formed,而左值赋值保持 well-formed。
请注意,声明赋值运算符会禁用隐式移动赋值,因此如果需要,您可能还需要定义它(也是默认的,并且可能在适当的情况下使用右值引用限定符)。
Why wouldnt this complain in the same way if Bar is a temporary and it doesnt have an specialized operator =?
因为隐式生成的赋值运算符不是ref-qualified.
Clearly this is a coding error if it were to be used this way
右值赋值并非普遍错误。对于一些应该表现得像引用的类型,右值的赋值是很自然的。这是因为赋值修改了引用的对象,而不是临时对象本身。
一个典型的用例是分配给右值std::tie
(来自cppreference的示例):
std::set<S> set_of_s; // S is LessThanComparable
S value{42, "Test", 3.14};
std::set<S>::iterator iter;
bool inserted;
// unpacks the return value of insert into iter and inserted
std::tie(iter, inserted) = set_of_s.insert(value);
是的,如果隐式运算符被限定,并且 non-qualified 需要显式声明,考虑到引用类型是例外而不是规范,这可能会更好。但这不是语言的样子,改变它是一种向后不兼容的改变。
是的,有一种方法可以通过删除这些方法使其成为编译错误:
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
请注意,这将禁用 auto-generation 其他运算符和构造函数,因此您必须全部定义它们:
struct Bar {
Bar()=default;
Bar(const Bar&) = default;
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
Bar& operator=(const Bar&)& =default;
Bar& operator=(Bar&&)& =default;
};