2015-09-25 103 views
4

下面這段代碼主要用於字符串視圖,其中T={char, const char}是主要預期的模板實例化目標。自動轉換模板< T>至模板<const T>

cmp函數應該類似於strcmp比較視圖。 問題是,雖然char*愉快地轉換爲const char*我不知道如何得到SVec<char>轉換爲SVec<const char>就像愉快。

最後一行(cout<<(cmp(rv, rvc));)不會編譯。我必須明確地進行轉換(cmp(SVec<const char>(rv), rvc))。可以像char*const char*那樣自動運行嗎?

代碼(大大簡化):

template <typename T> 
class SVec { 
    protected: 
     T* begin_; 
     size_t size_; 
    public: 

     SVec(T* begin, size_t size)   : begin_(begin), size_(size)   {}; 
     SVec(T* begin, T* end)     : begin_(begin), size_(end-begin) {}; 
     SVec(T* begin)       : begin_(begin) { while (*(begin++)) {}; size_ = begin - 1 - begin_; } 
               //^null element indicates the end 
     ///Conversion 
     operator SVec<const T>() const { return SVec<const T>(begin_, size_); } 
}; 

//General lexicographic compare 
template <typename T> 
inline int cmp(const SVec<const T>& l, const SVec<const T> & r){ 
    return 1; 
} 

//Char specialization 
template <> inline int cmp<char>(const SVec<const char>& l, const SVec<const char>& r){ 
    return 1; 
} 
//Explicit instantiation 
template int cmp<char>(const SVec<const char>& l, const SVec<const char>& r); 

#include <iostream> 

int main(){ 
    using namespace std; 

    char ar[] = "st"; 
    SVec<char> sv = ar; 
    SVec<const char> svc = "str"; 

    cout<<(cmp(SVec<const char>(sv), svc)); 

    cout<<(cmp(sv, svc)); 
} 
+0

您的問題不是轉換,而是扣除。用戶定義的轉換不考慮類型演繹,因此'cmp(const SVec &'無法在'cmp(sv,svc)'行中將'const T'與'char'進行匹配(不存在'T'這樣的'const T'等於'char') – dyp

+0

@dyp謝謝。'cmp (...)'修復了它。 – PSkocik

+0

@dyp你可以做出答案嗎? –

回答

3

所以,你應該做的第一件事就是讓cmp一個柯尼希運營商。

然後我們可以標記字符和非字符版本之間調度:

template <typename T> 
class SVec { 
    private: 
    static T* find_end(T* in) { 
     // I think while(*in)++in; would be better 
     // then the end is the null, not one-past-the-null. 
     while(*in++) {}; 
     return in; 
    } 
    protected: 
    T* begin_ = nullptr; 
    size_t size_ = 0; 
    public: 
    SVec() = default; 
    SVec(SVec const&) = default; 
    SVec(T* begin, size_t size) : begin_(begin), size_(size) {}; 
    SVec(T* begin, T* end) : SVec(begin, end-begin) {} 
    SVec(T* begin) : SVec(begin, find_end(begin)) {} 
    operator SVec<const T>() const { return SVec<const T>(begin_, size_); } 
    friend int cmp(SVec<T> l, SVec<T> r) { 
     return cmp_impl(l, r, std::is_same<std::decay_t<T>,char>{}); 
    } 
    private: 
    static int cmp_impl(SVec<const char> l, SVec<const char> r, std::true_type){ 
     return 1; 
    } 
    static int cmp_impl(SVec<const T> l, SVec<const T> r, std::false_type){ 
     return 1; 
    } 
    }; 

std::decay_tenable_if_t是C++ 14,但卻是typename垃圾_t稀少的版本只是短暫的版本。

注意我按值取代而不是const&:指針和size_t不值得引用傳遞。

我也轉發所有ctors到2個瓶頸。

...

的柯尼希操作friend int cmp使用ADL被發現。它是而不是的一個模板函數,而是一個爲每個template類實例生成的函數,這是一個重要的區別。

Koenig運算符避免了模板運算符的問題,同時允許它們根據模板的類型而變化。這種操作符只能通過ADL(依賴於參數的查找)找到。

然後根據if T是否爲char或不在編譯時調度到_impl重載(現在是常量正確)。