下面的文章主要是针对以T={char, const char}
为主要模板实例化目标的字符串 View 。
cmp函数应该类似于strcmp
来比较 View 。
问题是,虽然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));
}
最佳答案
因此,您可能应该做的第一件事就是将cmp
设为Koenig运算符。
然后,我们可以在char和non-char版本之间标记分发:
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_t
和enable_if_t
是C++ 14,但只是typename
垃圾邮件_t
-less版本的简短版本。注意,我按值而不是
const&
进行处理:指针和size_t
不值得通过引用传递。我还将所有ctor转发到两个瓶颈中。
...
Koenig运算符
friend int cmp
使用ADL进行查找。它不是模板函数,而是为每个template
类实例生成的函数,这是一个重要的区别。Koenig运算符避免了模板运算符的问题,同时允许它们随模板的类型而变化。只能通过ADL(依赖于参数的查找)找到这种运算符。
然后根据
_impl
是T
还是在编译时将其分派(dispatch)给char
重载(现在是const正确的)。关于c++ - 自动将template <T>转换为template <const T>,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32791505/