2017-07-11 61 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

您的發佈代碼有兩個主要問題。

  1. 編譯器不轉換B<int>A<int>推斷模板參數fooint。你必須幫助編譯器。用途:

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

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

    ,將解決只是問題的一半。

  2. 無論編譯器使用哪一個轉換函數,轉換函數都會生成一個臨時對象。臨時對象無法綁定到A<int>&。你將不得不使用

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

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

此外,friend申報A是不正確的。它聲明非模板函數fooA<T>friend。如果你想foo<T>是的A<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,並且temp不能綁定到非const引用參數。這就是爲什麼你的電話foo()無法編譯。

如果要改變輸入參數來取代一個const引用,它可以綁定到一個臨時對象。但是,A有一個複製構造函數,它將對一個B對象的const引用作爲輸入,所以您對foo()的調用可能仍不明確。在構建臨時對象B之後,編譯器是否應該使用B作爲輸入調用A拷貝構造函數,或者是否應該調用B轉換運算符,該運算符返回A?我不確定標準對此有何說法,或者編譯器如何實現這一點。

+1

這不會幫助一個iota。模板參數扣除將會失敗。 http://ideone.com/QoLDZ8 – StoryTeller

+0

什麼是複製構造函數,它接受B對象的const引用? – PerelMan

+0

@MarwanB我指的是'A(const B &b)' –