3 ms·
Like others I was struggling to find usefulness of this and what problems it solves. I admit, it seems like a stretch. There was a situation in which I needed
by emcrazyone 11y ago
Like others I was struggling to find usefulness of this and what problems it solves. I admit, it seems like a stretch. There was a situation in which I needed a template class to be implemented such that I wanted only certain types to be accepted one way and others a different way.
I implemented a stream buffer that can accept different types into the stream. Based on the type, the buffer would serialize and expand to accept the data.
To put this more succintly, an insert of unit8_t type would put a single byte into the stream buffer and an insert of uint16_t would put two bytes into the stream buffer. And I needed a way to make sure the types were plain old data types (int, char, uint8_t, uint16_t, uint_32_t, etc...)
Here is sample code:
template<typename T>
class TStream
{
private:
typedef TBuffer<T> stream_buffer;
stream_buffer mStream;
public:
TStream();
TStream(const TStream &rhs);
TStream::~TStream();
unsigned int Size() const;
unsigned int ByteStreamLength() const;
void Clear();
// some methods omitted for brevity
const T&operator[](unsigned int idx);
const T*operator[](unsigned int idx) const;
TStream<T> &operator=(const TStream &rhs);
TStream<T> &operator=(T const);
TStream<T> &operator=(unsigned char);
TStream<T> &operator=(bool);
TStream<T> &operator=(double);
// rest omitted for brevity
};
Doing this
TStream<unsigned char> ByteStream
causes ambiguity with
operator=(unsigned char).
I basically want operator=(unsigned char) to be omitted if T = unsigned char.
The way I solved this, without Concepts of course, was to use CRTP like so:
template<typename D, typename T, typename U>
struct implement_operator_plus_equals
{
implement_operator_plus_equals()
{
static_assert(std::is_base_of<implement_operator_plus_equals, D>::value, "CRTP failure" );
}
D* self() { return static_cast<D>(this); }
D const self() const { return static_cast<D const>(this); }
typedef D Self;
Self& operator+=( U u ) {
static_assert( (sizeof(U)%sizeof(T)) == 0, "Non integer number of Ts in a U" );
T* b = reinterpret_cast<T*>(&u);
T* e = b + sizeof(U)/sizeof(T);
for (T* it = b; it != e; ++it) {
self()->consume(*it);
return *self();
}
};
template<typename D, typename T>
struct implement_operator_plus_equals<D,T,T> {
implement_operator_plus_equals() {
static_assert(
std::is_base_of<implement_operator_plus_equals, D>::value, "CRTP failure"
);
// Have an operator+= that cannot be called, so using ...::operator+= is legal,
// but mostly harmless:
class block_call {};
void operator+=( block_call ) {}
}
};
I believe I could have solved this without CRTP using Concepts. Although my understanding is that Concepts follows a methodology of deny all, allow what is defined and there appears to be no way to allow all, deny what is specified as a Concept. In other words, Concepts only tell the compiler what is allowed and there appears to be no way to specify what is NOT allowed without some further "trickery."