Mar*_*ark 15 c++ language-lawyer visual-studio-2013 visual-studio-2015
我有一个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;
};
Run Code Online (Sandbox Code Playgroud)
我有以下代码:
const F a{3, 7};
const F b{5, 10};
auto result = F{a} *= b; // How does this compile?
Run Code Online (Sandbox Code Playgroud)
在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)'
Run Code Online (Sandbox Code Playgroud)
我的期望是F{a}创建一个非const临时副本,a然后operator *= (b)将临时对象分配给该临时副本result.我没想到临时是一个常数.有趣的是:auto result = F(a) *= b;在VS2015中编译没有错误,我认为应该在语义上相同.
我的问题是:VS2015或VS2013的行为是正确的?为什么?
非常感谢
Visual Studio 2015未生成正确的结果:
F{a}
Run Code Online (Sandbox Code Playgroud)
结果应该是一个prvalue(gcc和clang都有这个结果),但它产生一个左值.我使用OP的代码的以下修改版本来产生这个结果:
#include <iostream>
class 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<typename T>
struct value_category {
static constexpr auto value = "prvalue";
};
template<typename T>
struct value_category<T&> {
static constexpr auto value = "lvalue";
};
template<typename T>
struct value_category<T&&> {
static constexpr auto value = "xvalue";
};
#define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value
int main()
{
const F a{3, 7};
const F b{5, 10};
std::cout << "\n" << VALUE_CATEGORY( F{a} ) << "\n";
}
Run Code Online (Sandbox Code Playgroud)
给Luc Danton提示VALUE_CATEGORY()代码.
使用webcompiler的 Visual Studio 具有相对较新的版本,可生成:
lvalue
Run Code Online (Sandbox Code Playgroud)
在这种情况下必须是const才能产生我们看到的错误.虽然gcc和clang(看到它直播)产生:
prvalue
Run Code Online (Sandbox Code Playgroud)
这可能与同样令人困惑的Visual Studio bug std :: move of string literal有关 - 哪个编译器是正确的?.
注意我们可以使用const F得到与gcc和clang相同的问题:
using cF = const F ;
auto result = cF{a} *= b;
Run Code Online (Sandbox Code Playgroud)
因此,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方面也有所不同,据我所知,这与前一个问题没有关系.
我认为这是 VS2015 中的一个错误,因为如果您指定用户定义的复制构造函数:
F(const F&);
Run Code Online (Sandbox Code Playgroud)
或 make 变量a非常量代码将成功编译。
看起来对象的常量性已a转移到新创建的对象中。
| 归档时间: |
|
| 查看次数: |
378 次 |
| 最近记录: |