为不同的参数集专门化模板 class
Specialize template class for different parameter sets
假设我有一个像
这样的模板结构
template <typename T> struct Parser {
//specializations are expected to have these methods
inline static const byte* objectEnd(const byte* begin, const byte* end);
inline static const byte* tryRead(const byte* begin, const byte* end, T* obj);
}
它在不同的 classes 中使用,其中一些也是模板 classes(所以他们可能没有关于他们传递给 class 的内容的完整信息 Parser
作为参数)。
为任何给定类型实现 Parser
很容易,如下所示:
template<> struct Parser<text_line> {
inline static const byte* objectEnd(const byte* begin, const byte* end){
return helper::NextByteOrEnd<'\n'>(begin, end);
}
inline static const byte* tryRead(const byte* begin const byte* end, text_line* obj){
const byte* lf = objectEnd(begin, end);
obj = text_line(begin, lf);
return lf==end ? lf : lf+1;
}
}
我还可以针对一系列模板专门 Parser
:
template<int sz> struct Parser<be_uint<sz>> {
inline static const byte* objectEnd(const byte* begin, const byte* end){
return begin+be_uint<sz>::size > end ? begin : begin+be_uint<sz>::size;
}
inline static const byte* tryRead(const byte* begin const byte* end, be_uint<sz>* obj){
if(begin + be_uint<sz>::size > end) return begin;
obj = be_uint<sz>::read(begin);
return begin + be_uint<sz>::size;
}
}
但是如果我想 Parser
专门针对其他一些类型集怎么办?假设我有一个类型谓词,比如说,std::is_base_of<MyHeader, T>
,我想写类似
的东西
//not actual code - how would I write this?
template<typename Header> struct Parser<Header> {
static_assert(std::is_base_of<MyHeader, Header>::value, "Wrong!");
inline static const byte* objectEnd(const byte* begin, const byte* end){
//MyHeader-specific code here
}
inline static const byte* tryRead(const byte* begin const byte* end, Header* obj){
//MyHeader-specific code here
}
}
将可选参数添加到 Parser
的初始定义中,如
template <typename T, bool MyHeaderFlag = std::is_base_of<MyHeader, T>::value>
struct Parser { //...
似乎不是个好主意 - 我(或任何其他程序员)可能想使用其他谓词,例如 my_types::is_scientific<T>
.
这个问题似乎可以用 SFINAE 解决(有一个问题,如果一种类型适合多个谓词应该发生什么——我更希望它不会导致编译器错误,但这不是很重要,因为这样 Parser
专业化很可能放在 .cpp 文件中)。但是我找不到办法做到这一点。
需要明确的是,只要客户端代码可以编写类似
的内容,就没有限制保留“解析器”或其方法(甚至是模板)的确切定义
Parser<TypeArg>::objectEnd(block.begin, block.begin+block.size)
不关心 TypeArg
实际上是什么。
如果您想对某些类型集进行专门化,最好的方法是将第二个模板参数添加到您的基本模板。
您可以使用 bool
或实际键入并在专业化中使用 std::enable_if
。
我更喜欢第二种方式
template <typename T, typename = void> struct Parser {
//specializations are expected to have these methods
inline static const byte* objectEnd(const byte* begin, const byte* end);
inline static const byte* tryRead(const byte* begin, const byte* end, T* obj);
}
和专业化示例
template<typename Header>
struct Parser<Header, typename std::enable_if<std::is_base_of<MyHeader, Header>::value>::type> {
inline static const byte* objectEnd(const byte* begin, const byte* end){
//MyHeader-specific code here
}
inline static const byte* tryRead(const byte* begin, const byte* end, Header* obj){
//MyHeader-specific code here
}
}
假设我有一个像
这样的模板结构template <typename T> struct Parser {
//specializations are expected to have these methods
inline static const byte* objectEnd(const byte* begin, const byte* end);
inline static const byte* tryRead(const byte* begin, const byte* end, T* obj);
}
它在不同的 classes 中使用,其中一些也是模板 classes(所以他们可能没有关于他们传递给 class 的内容的完整信息 Parser
作为参数)。
为任何给定类型实现 Parser
很容易,如下所示:
template<> struct Parser<text_line> {
inline static const byte* objectEnd(const byte* begin, const byte* end){
return helper::NextByteOrEnd<'\n'>(begin, end);
}
inline static const byte* tryRead(const byte* begin const byte* end, text_line* obj){
const byte* lf = objectEnd(begin, end);
obj = text_line(begin, lf);
return lf==end ? lf : lf+1;
}
}
我还可以针对一系列模板专门 Parser
:
template<int sz> struct Parser<be_uint<sz>> {
inline static const byte* objectEnd(const byte* begin, const byte* end){
return begin+be_uint<sz>::size > end ? begin : begin+be_uint<sz>::size;
}
inline static const byte* tryRead(const byte* begin const byte* end, be_uint<sz>* obj){
if(begin + be_uint<sz>::size > end) return begin;
obj = be_uint<sz>::read(begin);
return begin + be_uint<sz>::size;
}
}
但是如果我想 Parser
专门针对其他一些类型集怎么办?假设我有一个类型谓词,比如说,std::is_base_of<MyHeader, T>
,我想写类似
//not actual code - how would I write this?
template<typename Header> struct Parser<Header> {
static_assert(std::is_base_of<MyHeader, Header>::value, "Wrong!");
inline static const byte* objectEnd(const byte* begin, const byte* end){
//MyHeader-specific code here
}
inline static const byte* tryRead(const byte* begin const byte* end, Header* obj){
//MyHeader-specific code here
}
}
将可选参数添加到 Parser
的初始定义中,如
template <typename T, bool MyHeaderFlag = std::is_base_of<MyHeader, T>::value>
struct Parser { //...
似乎不是个好主意 - 我(或任何其他程序员)可能想使用其他谓词,例如 my_types::is_scientific<T>
.
这个问题似乎可以用 SFINAE 解决(有一个问题,如果一种类型适合多个谓词应该发生什么——我更希望它不会导致编译器错误,但这不是很重要,因为这样 Parser
专业化很可能放在 .cpp 文件中)。但是我找不到办法做到这一点。
需要明确的是,只要客户端代码可以编写类似
的内容,就没有限制保留“解析器”或其方法(甚至是模板)的确切定义Parser<TypeArg>::objectEnd(block.begin, block.begin+block.size)
不关心 TypeArg
实际上是什么。
如果您想对某些类型集进行专门化,最好的方法是将第二个模板参数添加到您的基本模板。
您可以使用 bool
或实际键入并在专业化中使用 std::enable_if
。
我更喜欢第二种方式
template <typename T, typename = void> struct Parser {
//specializations are expected to have these methods
inline static const byte* objectEnd(const byte* begin, const byte* end);
inline static const byte* tryRead(const byte* begin, const byte* end, T* obj);
}
和专业化示例
template<typename Header>
struct Parser<Header, typename std::enable_if<std::is_base_of<MyHeader, Header>::value>::type> {
inline static const byte* objectEnd(const byte* begin, const byte* end){
//MyHeader-specific code here
}
inline static const byte* tryRead(const byte* begin, const byte* end, Header* obj){
//MyHeader-specific code here
}
}