2015-09-25 98 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重载(现在是常量正确)。