There is an easy way, and a legal way.
The easy way is to use SFINAE on the function in question. Sadly, as this results in a function template for which there is no valid specialization, this is technically an ill formed program (no diagnostic required). So avoid that.
The legal way would be to use CRTP.
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 ) {}
}
};
Then use it:
template<typename D,typename T>
struct plus_equals_helper:
public implement_operator_plus_equals< TStream<T>, T, int >,
public implement_operator_plus_equals< TStream<T>, T, unsigned char >,
public implement_operator_plus_equals< TStream<T>, T, bool >,
public implement_operator_plus_equals< TStream<T>, T, double >
{
// move += down from parents (to fix problem OP reported):
using implement_operator_plus_equals< TStream<T>, T, int >::operator+=;
using implement_operator_plus_equals< TStream<T>, T, unsigned char >::operator+=;
using implement_operator_plus_equals< TStream<T>, T, bool >::operator+=;
using implement_operator_plus_equals< TStream<T>, T, double >::operator+=;
};
template<typename T>
class TStream:
public plus_equals_helper< TStream<T>, T >
{
public:
void consume( T t ) { /* code */ }
using plus_equals_helper<TStream<T>, T>::operator+=;
TStream const& operator+=( T t ) { consume(t); return *this; }
};
this is legal, because the specializations that do nothing are perfectly ok.
On the other hand, the rule that all template functions must have at least one valid specialization is pretty obscure, and usually nothing really bad happens if you violate it. So you could just SFINAE disable your methods using a second unused default argument.