关于运算符重载和依赖于参数的查找,Visual Studio 10和GCC 4.5之间的哪个编译器是正确的?

| 我有以下代码:
class Foo;
class Bar;

class Bar {
public:
    Bar() {
    }

    Bar(Foo &foo) {
    }
};

class Foo {
public:
    Foo() {
    }
    Foo(Foo &foo) {
    }
    Foo(const Bar &bar) {
    }
};

Bar operator >> (const Bar &left, const Bar &right) { return Bar(); }

Foo a;
Foo b;
Foo c = a >> b;
在Visual Studio 10中,上述代码可以很好地编译:编译器识别出可以从
Foo&
实例化
Bar
,因此它调用适当的
operator >>
,然后返回
Bar
实例,并适当地调用构造函数
Foo(const Bar &)
。 但是,GCC 4.5不会编译以上代码。它输出以下错误:
error: no matching function for call to \'Foo::Foo(Foo)\'
note: candidates are: Foo::Foo(const Bar&)
note:                 Foo::Foo(Foo&)
note:                 Foo::Foo()
根据语言标准,为什么会发生上述情况,并且哪种编译器正确? 编辑: 由于存在
Foo(const Bar &)
,C ++为什么会由于
c = a >> b
而创建一个临时
Foo
对象?     
已邀请:
        这应该工作:
Foo c(a >> b);
此初始化语法为:
Foo c = a >> b;
被解释为
Foo c(Foo(a >> b));
是复制初始化,需要可访问的复制构造函数,该构造函数接受
const Foo&
。 从标准的第14节开始(用C ++ 0x编写):   初始化的形式(使用括号或=)通常是微不足道的,但是当初始化器或要初始化的实体具有类类型时,它就很重要。见下文。如果要初始化的实体不具有类类型,则带括号的初始化器中的expression-list应为单个表达式。      初始化形式
   T  x  =  a;
     以及参数传递,函数返回,引发异常(15.1),处理异常(15.3)和聚合成员初始化(8.5.1)都称为复制初始化。 [注意:复制初始化可能会调用移动(12.8)。 —尾注]      表单中发生的初始化
   T  x(a);
   T  x{a};
     以及新表达式(5.3.4),static_cast表达式(5.2.9),功能符号类型转换(5.2.3)以及基本和成员初始化程序(12.6.2)被称为直接初始化。
T x{a}
语法是C ++ 0x中的新增功能,所有其他规则与C ++ 03相同。 然后,适用以下规则(同一部分):      如果初始化是直接初始化,或者是复制初始化,其中源类型的cv不合格版本与目标的类相同,或者是该类的派生类,则考虑构造函数。列举了适用的构造函数(13.3.1.3),并通过重载分辨率(13.3)选择了最佳的构造函数。如此选择的构造函数将以初始化器表达式或expression-list作为其参数来初始化对象。如果没有构造函数适用,或者重载解决方案不明确,则初始化格式错误。   否则(即,对于其余的复制初始化情况),如13.3所述,列举可以从源类型转换为目标类型或(当使用转换功能时)为其派生类的用户定义转换序列。 1.4,最佳选择是通过过载分辨率(13.3)选择的。如果转换无法完成或模棱两可,则初始化格式错误。所选函数以初始化器表达式作为参数进行调用;如果函数是构造函数,则调用将初始化目标类型的cv不合格版本的临时类。临时变量是一个prvalue。然后,根据上面的规则,调用的结果(对于构造方法而言是临时的)将用于直接初始化作为复制初始化目标的对象。在某些情况下,允许通过将中间结果直接构造到要初始化的对象中来消除此直接初始化中固有的复制。参见12.2、12.8。        
这与重载或参数查找无关。通过定义ѭ18,您已禁用了默认副本构造函数
Foo(const Foo&)
的生成,这是从右值初始化
c
所必需的。添加具有Foo(const Foo&)签名的ctor,您的代码将正常运行。我不知道为什么VS10会编译它,但是我将尝试查找指定为什么不应该发生的子句。 开始了: §12.8(1)指定如果类X的第一个参数的类型为X&,const X&,volatile X&或const volatile X&类型并且没有其他参数或所有其他参数都具有默认值,则该类的非模板构造函数为副本构造函数。 §12.8(5)表示,如果我们不为X(上述任何形式)定义一个副本构造函数,则编译器将以X(const X&)形式定义一个副本构造函数。 因此,定义Foo(Foo&)定义了一个复制构造函数,因此编译器无法再隐式定义Foo(const Foo&)。     

要回复问题请先登录注册