我有一个C++类,它具有以下接口:
class F { public: F(int n, int d); // no other constructors/assignment constructors defined F& operator *= (const F&); F& operator *= (int); int n() const; int d() const; };
我有以下代码:
const F a{3, 7}; const F b{5, 10}; auto result = F{a} *= b; // How does this compile?
在Visual Studio(VS)2013下,注释行编译时没有错误.在VS2015下,产生错误C2678:
error C2678: binary '*=': no operator found which takes a left-hand operand of type 'const F' (or there is no acceptable conversion) note: could be 'F &F::operator *=(const F &)' note: or 'F &F::operator *=(int)' note: while trying to match the argument list '(const F, const F)'
我的期望是F{a}
创建一个非const临时副本,a
然后operator *= (b)
将临时对象分配给该临时副本result
.我没想到临时是一个常数.有趣的是:auto result = F(a) *= b;
在VS2015中编译没有错误,我认为应该在语义上相同.
我的问题是:VS2015或VS2013的行为是正确的?为什么?
非常感谢
Visual Studio 2015未生成正确的结果:
F{a}
结果应该是一个prvalue(gcc和clang都有这个结果),但它产生一个左值.我使用OP的代码的以下修改版本来产生这个结果:
#includeclass F { public: F(int n, int d) :n_(n), d_(d) {}; F(const F&) = default ; F& operator *= (const F&){return *this; } F& operator *= (int) { return *this; } int n() const { return n_ ; } int d() const { return d_ ; } int n_, d_ ; }; template struct value_category { static constexpr auto value = "prvalue"; }; template struct value_category { static constexpr auto value = "lvalue"; }; template struct value_category { static constexpr auto value = "xvalue"; }; #define VALUE_CATEGORY(expr) value_category ::value int main() { const F a{3, 7}; const F b{5, 10}; std::cout << "\n" << VALUE_CATEGORY( F{a} ) << "\n"; }
给Luc Danton提示VALUE_CATEGORY()代码.
使用webcompiler的 Visual Studio 具有相对较新的版本,可生成:
lvalue
在这种情况下必须是const才能产生我们看到的错误.虽然gcc和clang(看到它直播)产生:
prvalue
这可能与同样令人困惑的Visual Studio bug std :: move of string literal有关 - 哪个编译器是正确的?.
注意我们可以使用const F得到与gcc和clang相同的问题:
using cF = const F ; auto result = cF{a} *= b;
因此,Visual Studio不仅为我们提供了错误的值类别,而且还随意添加了一个cv-qualifier.
正如汉斯在他对你的问题的评论中指出的那样F(a)
产生了预期的结果,因为它正确地产生了一个prvalue.
C++标准草案的相关部分是5.2.3
[expr.type.conv]部分,其中说:
类似地,一个simple-type-specifier或typename-specifier后跟一个braced-init-list,用指定的braced-init-list创建一个指定类型direct-list-initialized(8.5.4)的临时对象及其值是临时对象作为prvalue.
请注意,据我所知,这不是"旧的MSVC左值投射错误".该问题的解决方案是使用/Zc:rvalueCast
哪个不能解决此问题.这个问题在不正确添加cv-qualifier方面也有所不同,据我所知,这与前一个问题没有关系.