2009-12-13 131 views
3

我有一個指針類的子集,它看起來像:C++模板和模糊問題

template <typename T> 
struct Pointer 
{ 
    Pointer(); 
    Pointer(T *const x); 
    Pointer(const Pointer &x); 
    template <typename t> 
    Pointer(const Pointer<t> &x); 

    operator T *() const; 
}; 

最後一個構造函數的目標是允許通過一個子類的Pointer,或者基本上任何類型的是可以隱式轉換爲T *。這個實際規則只能通過構造函數的定義來實施,編譯器實際上無法通過聲明單獨解決。如果我放棄它,並嘗試將Pointer<Sub>傳遞給構造函數Pointer<Base>,則會出現編譯錯誤,儘管通過operator T *()可能會有路徑。

雖然它解決了上述問題,但它創建了另一個。如果我有一個重載函數,其中一個超載需要一個Pointer<UnrelatedClass>,另一個需要Pointer<BaseClass>,並且我嘗試用Pointer<SubClass>來調用它,但是我在兩個重載之間產生了一個模糊性,目的是,後者的重載將被稱爲。

有什麼建議嗎? (希望我是足夠清晰的)

+0

這是更爲常見的使用大寫字母'U'額外的模板參數。小寫't'幾乎看起來像一個錯字。 – GManNickG 2009-12-13 21:43:57

+0

隱式轉換是一個壞主意。使用'T * get()'而不是'運算符T *()'。 shared_ptr做這樣的事情。 – 2009-12-13 21:49:38

回答

6

治癒你的問題被稱爲SFINAE(替換故障是不是一個錯誤)

#include "boost/type_traits/is_convertible.hpp" 
#include "boost/utility/enable_if.hpp" 

template<typename T> 
class Pointer { 
    ... 
    template<typename U> 
    Pointer(const Pointer<U> &x, 
     typename boost::enable_if< 
     boost::is_convertible<U*,T*> 
     >::type* =0) 
    : ... 
    { 
    ... 
    } 
    ... 
}; 

如果U *轉換爲T *的enable_if將不得不違約作廢一個typedef成員type。然後,一切都很好。如果U *不能轉換爲T *,則此typedef成員缺失,替換失敗,構造函數模板將被忽略。

這解決了您的轉換和模糊性問題。

在迴應評論:is_convertible看起來是這樣的:

typedef char one;   // sizeof == 1 per definition 
struct two {char c[2];}; // sizeof != 1 

template<typename T, typename U> 
class is_convertible { 
    static T source(); 
    static one sink(U); 
    static two sink(...); 
public: 
    static const bool value = sizeof(sink(source()))==1; 
}; 
+0

明白了,好主意。該項目暫時不使用提升。任何想法如何'is_convertible'的作品? – cvb 2009-12-13 22:00:46

+0

是的。隨時upvote。:) – sellibitze 2009-12-13 22:10:56

+0

會upvoted十倍,但我沒有註冊:) – cvb 2009-12-13 22:23:18

0

儘量讓有問題明確的構造函數,例如:

template <typename t> 
explicit Pointer(const Pointer<t> &x); 

和/或刪除operator T *() const; - 我想,這其中也將產生歧義。

編輯

檢查std::auto_ptr接口,並與你進行比較。至少他們解決了歧義。

+0

將'explicilt'添加到聲明中會產生相同的效果:它會生成一個編譯錯誤(2個重載都不能轉換所有參數類型...)。移除鑄造操作符並不能解決amibguity問題(無論如何,它是這個類的寶貴部分)。 – cvb 2009-12-13 21:49:09

+0

您可以添加代碼,使用指針,請添加(作爲註釋)出現編譯錯誤的位置,以及哪個錯誤。 – Frunsi 2009-12-13 21:58:11

+0

雖然鑄造操作員仍然可能是造成這種困境的原因(正如Alexey指出的那樣) ,隱式轉換是一個糟糕的主意:std :: auto_ptr沒有添加它,並且boost ptrs不會因爲相同的原因添加它(在某些情況下是ambuigity)。 – Frunsi 2009-12-13 22:00:52