2016-10-24 5 views
2
#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++:Clangにはオペレータがあふれていますが、GCCでは正しくありません。

(34): error C2593: 'operator =' is ambiguous

(26): note: could be 'Test &Test::operator =(Test &&)'

(25): note: or 'Test &Test::operator =(const Test &)'

(69): note: while trying to match the argument list '(Test, Wrapper)'

========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

クラン:

:34:7: error: use of overloaded operator '=' is ambiguous (with operand types 'Test' and 'typename std::remove_reference &>::type' (aka 'Wrapper'))

test = std::move(wrapperTest); // OK for GCC and ICC, not for Clang and Microsoft Visual C++

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

:25:8: note: candidate function

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

^

:26:8: note: candidate function

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

^

1 error generated.

+0

グラム 'のためのあなたの例である++'によってTest& operator=(Test &&test)を選ぶべきなのでしょうか?あなたは 'VC++'を提供しましたが、あなたの質問のタイトルは 'g ++'と書いてあります。どちらですか? Visual Studio C++は、GNU g ++とは異なるコンパイラです。 –

+0

私は混乱しています。彼らはどちらも同じ問題を言います: 'operator =()'はあいまいです。それはどう違うの? –

+0

@ThomasMatthews私は、このコードはGCCではうまくコンパイルされますが、ClangやVC++ではコンパイルできないと言いました。私はClangとVC++のエラーメッセージを出しました。 – Johnmph

答えて

3

私はgccとICCは正しいと思います。

test = std::move(wrapperTest); 

には候補者がこのコールのために一致しないので、それはほとんど1つの変換に要する操作に検討する、TestからWrapper<Test>&&を割り当てます。 Value categoriesから

When used as a function argument and when two overloads of the function are available, one taking rvalue reference parameter and the other taking lvalue reference to const parameter, an rvalue binds to the rvalue reference overload (thus, if both copy and move constructors are available, an rvalue argument invokes the move constructor, and likewise with copy and move assignment operators).

そしてNon-static member functions

A non-static member function can be declared with either an lvalue ref-qualifier (the token & after the function name) or rvalue ref-qualifier (the token && after the function name). During overload resolution, non-static cv-qualified member function of class X is treated as a function that takes an implicit parameter of type lvalue reference to cv-qualified X if it has no ref-qualifiers or if it has the lvalue ref-qualifier. Otherwise (if it has rvalue ref-qualifier), it is treated as a function taking an implicit parameter of type rvalue reference to cv-qualified X.

今、私たちはこれらの候補がありますoperator T&&() &&

  • によって

    • Test& operator=(Test &&test)これらの段落に基づいてoperator T const &() const &

    によって、コンパイラはoperator T&&() &&

  • +0

    おそらく、この回答は[オーバーロード解決](http://en.cppreference.com/w/cpp/language/overload_resolution)ページも参照する必要がありますか? –

    +1

    なぜコンパイラは '&&'過負荷を選択すべきですか? 2つの暗黙の変換シーケンスは、同じユーザー定義変換関数([\ [over.ics.rank \] /3.3)(http://eel.is/c)を含まないため、区別できないユーザー定義の変換シーケンスです++ draft/over.ics.rank#3))。私が知る限りでは、その呼び出しは実際にあいまいです。 – bogdan

    +0

    @bogdanしかし、std :: move(wrapperTest)はrvalueであり、変換演算子のref修飾子のために、rvalueバージョンを選択する必要がありますか? – Johnmph

    関連する問題