2017-07-11 20 views
0

ほとんどの操作が実装されているクラスAがあります。また、私はAのメンバーだけを含む別のクラスBを持っています。そして、私はAの操作をBに直接適用することができます。私は変換操作を定義します。しかし、コンパイラは "エラー: 'foo'への呼び出しに一致する関数はありません。暗黙の変換で何が問題なのですか?これを実装する方法は?ありがとう。テンプレート関数の暗黙的な変換

編集:演算子のオーバーロードをAに追加してBに直接使用させたい場合はどうすればよいですか?

template <typename T> struct B; 

template <typename T> 
struct A { 
    A(const B<T>& b) {} // Conversion from B to A, way 1 
    friend void foo(const A&); 
    // Addition 
    friend A operator+(const A&, const A&); 
}; 

template <typename T> 
void foo(A<T>& a) {} 

// Addition 
template <typename T> 
A<T> operator+(const A<T>& a1, const A<T>& a2) { return A<T>(); } 

template <typename T> 
struct B { 
    B() {} 
    A<T> a; 
    operator A<T>() { return a; } // Conversion from B to A, way 2 
    // Addition 
    B(const A<T>& a) : a(a) {} 
}; 

int main() 
{ 
    B<int> b; 
    foo(b); 
    auto bb = b+b; 
} 
+1

'foo'はテンプレートです。あなたは議論の控除を必要とする方法でそれを呼び出します。変換はできません。 – StoryTeller

+0

@StoryTellerそれを正しくするために何が必要です – zhangwfjh

答えて

4

投稿されたコードには2つの重大な問題があります。

  1. コンパイラがintするfooためのテンプレートパラメータを推定するA<int>B<int>を変換しません。あなたはコンパイラを助ける必要があります。用途:

    foo<int>(B<int>()); 
    

    または

    foo(static_cast<A<int>>(B<int>())); 
    

    半分しか問題を解決します。

  2. 変換関数は、どちらがコンパイラによって使用されていても、一時オブジェクトになります。一時オブジェクトはA<int>&にバインドできません。あなたはまた、Afriend宣言は適切ではない

    template <typename T> void foo(A<T>) {} 
    

    または

    template <typename T> void foo(A<T> const&) {} 
    

を使用する必要があります。非テンプレート関数fooは、friendA<T>と宣言されています。 foo<T>friendA<T>としたい場合は、コードを少し変更する必要があります。

// Declare the class template A first. 
template <typename T> class A; 

// Declare the funtion template foo next. 
template <typename T> void foo(A<T>); 

// Declare foo<T> to be friend of A<T> in the definition of A. 

template <typename T> 
struct A { 
    ... 
    friend void foo<>(A); 
}; 

ここでは私のため正常にビルド完全なプログラムです。

template <typename T> struct B; 
template <typename T> struct A; 
template <typename T> void foo(A<T> a); 

template <typename T> 
struct A { 
    A(const B<T>& b) : x{b.a.x} {} // Conversion from B to A, way 1 
    A(T x) : x{x} {} 
    T x; 
    friend void foo<>(A); 
}; 

template <typename T> 
void foo(A<T> a) {} 

template <typename T> 
struct B { 
    B() : a{0} {} 
    A<T> a; 

    // This is not necessary for conversion of B<T> to A<T> 
    // operator A<T>() { return a; } // Conversion from B to A, way 2 
}; 

int main() 
{ 
    foo<int>(B<int>()); 
    foo(static_cast<A<int>>(B<int>())); 
} 
+0

ありがとうございました。私の理解では、Aの演算子をオーバーロードすると、Bのためにそれを使用する些細な方法はありません。コンパイラは型を推論できないためです。そうですか? (あなたは私の編集を見ることができます) – zhangwfjh

+0

@zhangwfjhあなたの編集はあなたが直面している問題を変更しません。テンプレートパラメータの控除の場合、コンパイラはユーザー定義の変換を実行しません。それが主な問題です。 –

0

foo()は、非const参照を入力として受け取ります。 Bの変換演算子は一時的なAオブジェクトを返します。一時参照は非const参照パラメータにバインドできません。それでfoo()へのあなたの呼び出しがコンパイルに失敗する理由です。

代わりにconst参照を取るように入力パラメータを変更する場合は、tempオブジェクトにバインドできます。しかし、Aには、Bオブジェクトへのconst参照を入力として受け取るコピーコンストラクタがあるため、foo()への呼び出しはあいまいになることがあります。 temp Bオブジェクトを作成した後、コンパイラはBをコピーコンストラクタAと呼び出すか、Aを返すB変換演算子を呼び出す必要がありますか?私はその標準について何が言及されているのか、あるいはコンパイラがそれをどのように実装しているのかは分かりません。

+1

それは1つのイオタを助けません。テンプレート引数の控除はまったく同じになりません。 http://ideone.com/QoLDZ8 – StoryTeller

+0

Bオブジェクトのconst参照をとるコピーコンストラクタとは何ですか? – PerelMan

+0

@MarwanB私は 'A(const B &b)'を指しています。 –

関連する問題