在Clang上重载了操作符歧义但在GCC上没有重载,哪一个是正确的?

时间:2016-10-24 15:19:47

标签: c++ gcc clang overload-resolution

#include <iostream>


template <typename T>
struct Wrapper {
    operator T const &() const & {
        std::cout << "Wrapper::operator T const &() const &\n";
        return _obj;
    }

    operator T&() & {
        std::cout << "Wrapper::operator T&() &\n";
        return _obj;
    }

    operator T&&() && {
        std::cout << "Wrapper::operator T&&() &&\n";
        return std::move(_obj);
    }

private:
    T _obj;
};

struct Test {
    Test& operator=(Test const &test) {
        std::cout << "Test& Test::operator=(Test const &)\n";
        return *this;
    }

    Test& operator=(Test &&test) {
        std::cout << "Test& Test::operator=(Test &&)\n";
        return *this;
    }
};

int main() {
    Test test;
    Wrapper<Test> wrapperTest;

    test = wrapperTest;               // OK for all
    test = std::move(wrapperTest);    // OK for GCC and ICC, not for Clang and VC++

    return 0;
}

VC ++:

  

(34):错误C2593:'operator ='不明确

     

(26):注意:可以是'Test&amp; Test :: operator =(Test&amp;&amp;)'

     

(25):注意:或'Test&amp; Test :: operator =(const Test&amp;)'

     

(69):注意:在尝试匹配参数列表'(Test,Wrapper)'

时      

==========构建:0成功,1失败,0最新,0跳过==========

Clang:

  

:34:7:错误:使用重载运算符'='是不明确的(操作数类型'Test'和'typename std :: remove_reference&amp;&gt; :: type'(又名'Wrapper'))

     

test = std :: move(wrapperTest); //适用于GCC和ICC,不适用于Clang和Microsoft Visual C ++

     

~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~

     

:25:8:注意:候选功能

     

测试和安培; operator =(Test const&amp; test){std :: cout&lt;&lt; “Test&amp; Test :: operator =(Test const&amp;)\ n”;返回*这个; }

     

^

     

:26:8:注意:候选功能

     

测试和安培; operator =(Test&amp;&amp; test){std :: cout&lt;&lt; “Test&amp; Test :: operator =(Test&amp;&amp;)\ n”;返回*这个; }

     

^

     

生成了1个错误。

1 个答案:

答案 0 :(得分:4)

我认为gcc和icc是正确的。

test = std::move(wrapperTest);

Wrapper<Test>&&分配给Test,因为没有候选人匹配此次调用,它会考虑最多需要1次转换的操作。

来自Value categories

  

当用作函数参数并且当函数的两个重载可用时,一个采用rvalue引用参数而另一个采用左值引用const参数,rvalue绑定到rvalue引用重载(因此,如果同时复制和移动构造函数可用,rvalue参数调用移动构造函数,同样使用复制和移动赋值运算符)。

Non-static member functions

  

非静态成员函数可以使用左值ref-qualifier(函数名后面的标记&amp;)或rvalue ref-qualifier(标记&amp;&amp;函数名后面)声明。在重载解析期间,类X的非静态cv限定成员函数被视为一个函数,如果它没有ref-qualifiers或者它具有lvalue ref-qualifier,则将带有lvalue类型的隐式参数引用到cv-qualified X 。否则(如果它有rvalue ref-qualifier),它被视为一个函数,它采用类型为rvalue的隐式参数来引用cv-qualified X.

现在,我们有这些候选人:

  • Test& operator=(Test &&test) operator T&&() &&
  • Test& operator=(Test const &test) operator T const &() const &

根据这些段落,编制者应从Test& operator=(Test &&test)

选择operator T&&() &&