Suppose I have a template struct like
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);
}
It is used in different classes, some of which are also template classes (so they may not have full info about what class they pass to Parser
as a parameter).
Implementing Parser
for any given type is easy, like this:
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;
}
}
I can specialize Parser
for a family of templates, as well:
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;
}
}
But what if I want to specialize Parser
for some other set of types? Suppose I have a type predicate, say, std::is_base_of<MyHeader, T>
and I want to write something like
//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
}
}
Adding optional parameters to the initial definition of Parser
, like
template <typename T, bool MyHeaderFlag = std::is_base_of<MyHeader, T>::value>
struct Parser { //...
doesn't seem like a good idea - I (or any other programmer) may want to use other predicates, say, my_types::is_scientific<T>
.
The problem seems like something you could resolve with SFINAE (there's a problem of what should happen if one type fits several predicates - I prefer that it wouldn't result in compiler error, but it isn't very important since such Parser
specializations are likely to be palced in .cpp-files). But I couldn't find a way to do this.
Just to be clear, there is no constraint on preserving the exact definition of `Parser' or its methods (or even it being a template), as long as client code can write something like
Parser<TypeArg>::objectEnd(block.begin, block.begin+block.size)
without caring what TypeArg
actually is.