2016-05-06 16 views
3

C++ 11標準に従って、次のコードの正しい出力は何ですか?ユーザー定義の変換演算子を使用した関数テンプレートの過負荷解決

#include <iostream> 

template <typename X> 
class A 
{ 
public: 
    A() 
    { 
     std::cout << "A::A" << std::endl; 
    } 
    A(const A<X>&) 
    { 
     std::cout << "A::A(const A<X>&)" << std::endl; 
    } 
    A<X>& operator = (const A<X>&) 
    { 
     std::cout << "A::opeartor =(conat A&)" << std::endl; 
     return *this; 
    } 
}; 

void* GetData() 
{ 
    // return data based on some condition 
    static A<int> a; 
    return &a; 
} 

class P 
{ 

public: 
    template <typename T> 
    operator T&() 
    { 
     void* pData = GetData();    
     std::cout << "P::operator T&()" << std::endl; 
     return *(reinterpret_cast<T*>(pData)); 
    } 

    operator A<int>() 
    { 
     std::cout << "P::opeartor A<int>" << std::endl; 
     return A<int>(); 
    } 
}; 

int main(int /*argc*/, char** /*argv*/) 
{ 
    P objP; 
    A<int> objA = objP; // case 1 
    objA = objP; // case 2 
    return 0; 
} 

次の出力を出力します。

P::opeartor A<int> 
A::A 
A::A 
P::operator T&() 
A::opeartor =(conat A&) 

VS2015は、次のように出力を生成します。

A::A 
P::operator T&() 
A::A(const A<X>&) 
P::operator T&() 
A::opeartor =(conat A&) 

ケース1

VS2015は、gccと打ち鳴らすが、非テンプレートのバージョンを選ぶように、テンプレートのバージョンを選びます。

ケース2

すべての3つのコンパイラは、テンプレートのバージョンを選択します。

C++ 11標準を参照してこの動作をどのように説明できますか?

+0

疑いがある場合は、VSが準拠していないとします。 :) – erip

答えて

3

MSVCが間違っています。ここでの動作は、宛先タイプが候補タイプのセットに影響する参照タイプかどうかによって異なります。オブジェクト(A<int> objA = objP;)のコピー初期化において

  • は、[dcl.init]/17に適用される規則は、宛先タイプがA<int>ある候補セットが、そのことは、両方の変換関数を含む規則の下で、[over.match.copy]によって支配されていることを言います。それらは結ばれており、テンプレート/非テンプレートタイブレイカーは非テンプレートを選択します。参照const A<int>&operator=のパラメータ)の初期化で

  • [dcl.init.ref]/5のみ変換機能を有し、最初のオブジェクトへの左辺値の参照を初期化、[over.match.ref]によって指定された候補セットとオーバーロード解決を行うことを言っている、適用参照を返す。

    このように、唯一の候補はテンプレートです。実行可能であり、選択されています。非テンプレートは考慮されていません。

これはまた、そこにはあなたがA<int>のコンストラクタのオーバーロードの解決を行う、とA<int>年代のconst A<int>&パラメータを初期化しようとしますコンストラクタをコピーするためA<int> objA(objP);は、テンプレートを使用することを意味します。

+1

1つの詳細を指摘する:参照を初期化するとき、参照を直接*直接*にする変換関数が優先されます。すなわち、変換関数テンプレートが存在しない場合、「演算子A 」が選択されます。これは、直接/間接バインディングと過負荷解決の2段階の手順です。 – dyp

+0

(ただし、2番目の最後の箇条書き*「T1またはT2がクラスタイプの場合[...]」*は直接バインディングと見なされます) – dyp