2017-02-03 20 views
1

私は次のコードスニペットを持っている:複数の定義

template < typename T1, typename T2 > 
class Test 
{ 
    public: 
    Test() = default; 

    private:  
    template < typename T1_, typename T2_ > 
    friend Test< T1_, T2_ > operator*(const Test< T1_, T2_ >& lhs, const Test< T1_, T2_ >& rhs) 
    { 
     return Test< T1_, T2_ >(); 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    { 
     Test< int, int > t1; 
     Test< int, int > t2; 
     Test< int, int > t3 = t1 * t2; 
    } 

    { 
     Test< double, double > t1; 
     Test< double, double > t2; 
     Test< double, double > t3 = t1 * t2; 
    } 
} 

打ち鳴らす3.9でのコードは、私は次のエラーを取得するのgcc 6.3.1で、細かいコンパイル:

redefinition of ‘template<class T1_, class T2_> Test<T1_, T2_> operator*(const Test<T1_, T2_>&, const Test<T1_, T2_>&)’ 
    friend Test< T1_, T2_ > operator*(const Test< T1_, T2_ >& lhs, const Test< T1_, T2_ >& rhs) 

正しいコンパイラは?

私が疑うgccの場合、どのようにしてテンプレート演算子*をクラス内で正しく宣言できますか?引数依存のルックアップのためには、クラス定義が必要です。

答えて

3

Testのすべてのインスタンスは、それらの署名がT1又はT2に依存しないように同一であるテンプレートoperator*を、定義としてGCCが、正確です。 operator*ニーズがTestの特定のインスタンス化のためだけの過負荷、ここではテンプレートではない:

template < typename T1, typename T2 > 
class Test 
{ 
    friend Test operator*(const Test& lhs, const Test& rhs) 
    { 
     return Test(); 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    { 
     Test< int, int > t1; 
     Test< int, int > t2; 
     Test< int, int > t3 = t1 * t2; 
    } 

    { 
     Test< double, double > t1; 
     Test< double, double > t2; 
     Test< double, double > t3 = t1 * t2; 
    } 
} 

この代わりにoperator*の二つの非テンプレートのオーバーロード、Testの各インスタンス化のための1つを定義します。

+0

私は演算子テンプレートが必要です。しかし、クラス内の友人宣言とクラス定義外は、コンパイルエラーを解決しました。ありがとうございました! – Trevir

+0

@Trevirなぜそれをテンプレートにする必要がありますか? –

+0

異なるタイプのオブジェクトを乗算する。 'Test < int, int > t1、Test t2; auto t3 = t1 * t2'は有効でコンパイルが必要です。 – Trevir