string foo() { return "hello"; }
int main()
{
//below should be illegal for binding a non-const (lvalue) reference to a rvalue
string& tem = foo();
//below should be the correct one as only const reference can be bind to rvalue(most important const)
const string& constTem = foo();
}
std::string&
std::string
类型的非const引用无效
std::string
转换为std::string &
非const
引用只能绑定到左值&&
,而是在演示代码中,我只是使用非const左值引用!能否帮助我解释一下VS2010的行为?这是一个错误!? 感谢
答案 0 :(得分:11)
这是VS编译器的已知问题/功能。他们总是允许这样做,并且似乎没有任何推动去除扩展。
答案 1 :(得分:9)
编译器将在启用“禁用语言扩展”时发出错误,并在/ W4处发出警告。但是,删除此代码将破坏以前编译的代码,Microsoft非常不愿意这样做。这也是他们无法修复SFINAE支持的原因。
答案 2 :(得分:0)
Visual Studio的很多年和很多版本以后,我们仍然有这种“扩展”,这会引起意外和头痛。 igh ...
解决方法是将警告C4239变成错误。这将防止MSVC编译试图将非const左值引用绑定到临时代码的代码,并给您带来清晰的编译器错误。只需将/we4239
添加到编译器定义或cl
命令行参数中即可。
在Visual Studio中:
项目属性> C / C ++>所有选项>将特定警告视为错误>添加4239
,并确保用分号分隔任何其他数字。
在CMake中:
if(MSVC)
add_definitions("/we4239")
endif()
这似乎比使用/Za
的{{3}}更好,后者正式不建议这样做。在我的大型代码库中,添加/Za
会导致Microsoft自己的winnt.h
标头产生1500多个编译器错误。
答案 3 :(得分:-1)
这个问题有一个更糟糕的变种:
class Foo {
int _val;
public:
Foo(int v) : _val(v) {}
void F() { std::cout << _val << std::endl; }
};
class Bar {
Foo& f;
public:
Bar(Foo& f) : f(f) {}
void F() { f.F(); }
};
int main() {
Bar b(Foo(3));
b.F();
}
那么:在调用b.f
期间b.F()
点是什么意思?上面的示例使用VS2013默认的Debug设置编译,运行时不会崩溃并打印3
,但我怀疑任何更复杂的示例都会导致堆栈损坏。如果没有,并且编译器正在做一些“聪明”的工作,那么我猜它真正做的是:
class Foo {
int _val;
public:
Foo(int v) : _val(v) {}
void F() { std::cout << _val << std::endl; }
};
class Bar {
Foo f;
public:
Bar(Foo&& f) : f(f) {}
void F() { f.F(); }
};
int main() {
Bar b(Foo(3));
b.F();
}