基本上,该示例说明了一切:分配给std :: chrono文字-不给出错误消息。 我尝试了gcc,clang和vc(c ++ 17),所有这些编译器都接受了它。 这是预期的行为吗?
#include <chrono>
using namespace std::chrono_literals;
int main()
{
10ms += 1ms; // would expect error here
12ms = 10ms; // and here
// 3 = 4; // like here
return 0;
}
答案 0 :(得分:25)
std :: chrono文字是左值吗?
不。 std::chrono_literals
是prvalue。
这是预期的行为吗?
这是标准所规定的。
这些值属于类类型。只要该类是可分配的,并且可以为该类类型的右值分配 1 ,并且它们的赋值运算符重载不符合左值引用的条件。像所有成员函数一样,类的赋值运算符默认情况下不是lvalue ref限定的,并且几乎没有任何标准类具有这种限定的重载 2 -我不知道任何,但是如果有,{{ 1}}不是其中之一。
请注意,文字未修改。左操作数是一个临时对象,在这种情况下将被丢弃。
另一个简单的分配右值的示例:
std::chrono::duration
1 这实际上是一个有用的功能,尽管用例并不多。这是一个有用的示例:
std::string{"temporary"} = "this is pointless, but legal";
2 在C ++ 11之前,没有ref限定符,因此可以分配所有可分配类类型的右值。为了保持向后兼容性,不能更改默认值,也不能更改预先存在的类(至少在没有弃用期限的情况下)。 std::vector<bool> vec{true, false, true};
vec[1] = true; // vec[1] is an rvalue
是在C ++ 11中添加的,因此它本可以具有合格的赋值运算符,但是标准作者似乎更喜欢不限定其赋值运算符。
答案 1 :(得分:16)
std::chrono
文字不是左值。它们可能看起来像这样,但是您看到的实际上是r值对赋值运算符的调用。为什么允许这样做?具体来说,因为成员分配运算符
constexpr duration& operator+=(const duration& d)
由[time.duration.arithmetic]/9指定的不使用任何ref限定词,这表示不拒绝被r值调用。
与下面的示例比较(在上面的duration
中实现)
struct Foo {
unsigned long long i;
constexpr Foo& operator+=(const Foo& d) { return *this; }
};
constexpr Foo operator"" _Foo (unsigned long long i) {
return Foo{i};
}
int main() {
1_Foo += 2_Foo; // OK!
}
与以下示例相比,显式地使用&
ref限定符隐式禁止调用r值:
struct Foo {
unsigned long long i;
constexpr Foo& operator+=(const Foo& d) & { return *this; }
};
constexpr Foo operator"" _Foo (unsigned long long i) {
return Foo{i};
}
int main() {
1_Foo += 2_Foo; // error: no viable overloaded '+='
}
,或者下面的示例,明确删除了r值重载:
struct Foo {
unsigned long long i;
constexpr Foo& operator+=(const Foo& d) & { return *this; }
constexpr Foo& operator+=(const Foo& d) && = delete;
};
constexpr Foo operator"" _Foo (unsigned long long i) {
return Foo{i};
}
int main() {
1_Foo += 2_Foo; // error: overload resolution selected deleted operator '+='
}
有关r值限定符的详细信息以及如何使用它们以禁止分配r-value,请参见例如以下问答: