C++ 一个VS2010错误?允许在没有警告的情况下将非常量引用绑定到右值? GCC是给出编译错误的好方法:从类型为std::string的临时变量初始化类型为std::string&的非常量引用无效 VS2008还不错,至少它给出了一个编译警告: 警告C4239:使用了非标准扩展:“正在初始化”: 从std::string到std::string&非常量的转换 引用只能绑定到左值 下面是一个有问题的问题-VS2010(SP1)comples没有任何问题 错误或警告,为什么??!! 我知道VS2010中的右值引用可以用来绑定右值,但我没有使用&&,相反,在演示代码中,我只是使用了非常量左值引用

C++ 一个VS2010错误?允许在没有警告的情况下将非常量引用绑定到右值? GCC是给出编译错误的好方法:从类型为std::string的临时变量初始化类型为std::string&的非常量引用无效 VS2008还不错,至少它给出了一个编译警告: 警告C4239:使用了非标准扩展:“正在初始化”: 从std::string到std::string&非常量的转换 引用只能绑定到左值 下面是一个有问题的问题-VS2010(SP1)comples没有任何问题 错误或警告,为什么??!! 我知道VS2010中的右值引用可以用来绑定右值,但我没有使用&&,相反,在演示代码中,我只是使用了非常量左值引用,c++,visual-studio-2010,reference,lvalue,rvalue,C++,Visual Studio 2010,Reference,Lvalue,Rvalue,有人能帮我解释一下VS2010的行为吗?是虫子吗!? 谢谢这是VS编译器的一个已知问题/功能。他们总是允许这样做,而且似乎没有任何力量去删除该扩展。编译器将在禁用语言扩展打开时发出错误,并在/W4处发出警告。然而,删除此代码将破坏以前编译的代码,Microsoft非常不愿意这样做。这也是他们不修复SFINAE支持的原因。这个问题有一个更糟糕的变体: string foo() { return "hello"; } int main() { //below should be illeg

有人能帮我解释一下VS2010的行为吗?是虫子吗!?
谢谢

这是VS编译器的一个已知问题/功能。他们总是允许这样做,而且似乎没有任何力量去删除该扩展。

编译器将在禁用语言扩展打开时发出错误,并在/W4处发出警告。然而,删除此代码将破坏以前编译的代码,Microsoft非常不愿意这样做。这也是他们不修复SFINAE支持的原因。

这个问题有一个更糟糕的变体:

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();   
}

几年后,许多版本的VisualStudio仍然使用这个“扩展”,这会带来惊喜和头痛。叹息

解决方法是简单地将警告C4239变成一个错误。这将阻止MSVC编译试图将非常量左值引用绑定到临时引用的代码,并给出一个清晰的编译器错误。只需将
/we4239
添加到编译器定义或
cl
命令行参数

在Visual Studio中: 项目属性>C/C++>所有选项>将特定警告视为错误>添加
4239
,并确保用分号分隔任何其他数字

在CMake中:

if(MSVC)
添加定义(“/we4239”)
endif()

这似乎比官方不推荐的
/Za
要有效得多。在我庞大的代码库中,添加
/Za
从微软自己的
winnt.h
头中导致超过1500个编译器错误。

您的警告设置是什么?也许是您的配置改变了,而不是它们的实现?我使用VS2008已经有一段时间了,但最近安装了VS2010,所以VS10应该使用它的默认设置…那么我担心警告树名不够高。使用
\W4
激活
4xxx
范围内的警告。@Gob00st-因此投诉是Deafolt设置不是您需要的设置?@Bo Persson-我对VS2010的默认设置不满意,它不会给出任何错误或警告!VS2008确实给出了一个警告,它比任何东西都好。为什么MS最初允许使用这个非法C++?这个特定的引用规则应该相当旧(98或03标准)?@ GOB0ST:这是一个绕过任意C++限制的扩展。我个人认为,绑定应该被允许或不允许,而当前允许的一半实际上是一种尴尬的状态。完全不允许会消除一整类错误,尽管这会很痛苦,但完全允许会纠正规范。@Gob00st-MS有一些旧代码是在规则修复之前编写的(他们的客户也可能有)。他们认为支持旧代码比支持新标准更重要。也可以关闭扩展(因此无法编译某些Windows标头)。请注意,如果
f
是常量引用,则存在相同的问题,这是标准所允许的。可能值得一提的是,在VS2010中,警告已从/W3移到/W4。
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();
}
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();
}