2

我正在寫一個包裝模板類,它可以包裝一個任意類型,並用一些額外的語義灌輸它,但我無法弄清楚如何獲得重載解析正常工作。當通常通過比較競爭轉換序列的等級來解決的轉換不能由編譯器推斷時出現問題,因爲所討論的類型是模板參數而不是函數參數。例如,C++使用模板參數來解決重載

#include <type_traits> 

template <typename T> class Wrapper { 
    T val; 

public: 
    Wrapper() = default; 
    template <typename U> Wrapper(Wrapper<U> x) : val(x.val) {} 
}; 

void foo(Wrapper<const char *>) {} 
void foo(Wrapper<bool>) {} 

int main() { 
    Wrapper<char *> cp; 
    foo(cp); 
} 

這裏,對foo()的調用是不明確的。期望的行爲將會是編譯器選擇void foo(Wrapper<const char *>),因爲如果cp代替char *foo代替void foo(const char *),它將會如此。這可能嗎?

編輯:感謝大家的快速反應,但也許我應該更清楚。我上面給出的僅僅是一個例子。我需要的是對以下問題的一般解決方案:給定任意類型T,UV,假設C++的內置過載分辨率會優於TU而不是TV。那麼我怎樣才能確保C++更喜歡Wrapper<T> - >Wrapper<U>高於Wrapper<T> - >Wrapper<V>

我做了這個澄清,因爲它似乎是專門解決重載決議的某些方面,如cv-qualifiedness,而我真的需要一個通用的解決方案。

回答

1

這裏的問題是,兩個ov由於模板的原因,分辨率在分辨率中具有完全相同的權重。

如果您想要重載解析發生,您必須引入重載解析。
這可以通過添加相應的類型作爲第二個(未使用)參數來完成:

void foo(Wrapper<const char *>, const char *) 
void foo(Wrapper<bool>,   bool) 

用下面的別名在您的包裝幫助:)

using value_type = T; 

以下富(功能選擇最佳的過載:

template <typename W> 
void foo(W && w) { 
    foo(std::forward<W>(w), typename std::remove_reference_t<W>::value_type{}); 
} 

DEMO

+0

我認爲這是最好的答案,儘管這不是我一直期待的。這種技術是我提出的過載問題的一般解決方案......我希望有一個解決方案,它不需要重載函數的包裝,但我現在確信這是不可能的。謝謝! – Fidget324

0

您在char*前面缺少const

聲明如下所述。它應該工作。

Wrapper<const char *> cp; 

下面是測試結果

http://rextester.com/FNOEL65280

+1

OP想要一種方式來進行轉換工作。這只是迴避問題 – NathanOliver

1

你需要做的構造貪心不足。這可以通過SFINAE做到:

template <typename T> 
using remove_const_from_pointer_t = 
    std::conditional_t<std::is_pointer<T>::value, 
    std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>, T>; 

template <typename T> 
class Wrapper { 
    T val; 

    template <typename U> 
    friend class Wrapper; 

public: 
    Wrapper() = default; 

    template < 
    typename U, 
    std::enable_if_t< 
     std::is_same<U, remove_const_from_pointer_t<T>>::value, int*> = nullptr> 
    Wrapper(Wrapper<U> x) : val(x.val) {} 
}; 

你可能想嘗試this,而不是我remove_const_from_pointer_t

另請注意,我不得不添加一個friend聲明。

編輯:這並不只在一個void foo(Wrapper<bool>)超載的情況下工作,你必須SFINAE從Wrapper的構造應用移動直接向此重載:

template < 
    typename T, 
    std::enable_if_t< 
    std::is_same<std::remove_const_t<T>, char>::value, int*> = nullptr> 
void foo(Wrapper<T *>) { } 
+1

謝謝你的迴應,但它似乎只解決了我給的例子,可能還有一些類似的情況。請看我最近的編輯。 – Fidget324

0

有幾件事情可以做:

  1. 只需從包裝< T * >禁止建設包裝<布爾>。這樣的事情是非常容易出錯
  2. 使用SFINAE
#include <type_traits> 

template <typename T> class Wrapper { 
    T val; 
public: 
    T getVal() const { 
    return val; 
    } 
    Wrapper() = default; 
    template <typename U, 
      class = typename std::enable_if<std::is_same<typename std::remove_cv<typename std::remove_pointer<T>::type>::type, 
                 typename std::remove_pointer<U>::type>::value>::type> 
    Wrapper(Wrapper<U> x) : val(x.getVal()) {} 
}; 

void foo(Wrapper<const char *>) {} 
void foo(Wrapper<bool>) {} 

int main() { 
    Wrapper<char *> cp; 
    foo(cp); 
} 

使用這個你可以只允許一組特定的轉換,即:X * - >常量X *,整數類型之間的轉換,等等。

更新:不幸的是,似乎你不能模仿標準的重載決策規則,因爲你可以使用在轉換運營商,並在重載方面,它具有常秩

+0

哎呀。如果你的更新是真的,那麼我會非常失望。我不是那麼暗暗希望別人會不同意! – Fidget324

+0

我暗自分享那個希望 –