我已经看到我的问题的各种形式也得到了回答/回复,但我仍然很难弄清楚如何省略我的编译器状态不明确的函数。
我有一个旨在处理数据流的类。我有重载=和+ =运算符,以便流类可以通过将其转换为模板类型T来使用其他类型的数据。
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
};
这样做
TStream<unsigned char> ByteStream
导致含糊不清
operator=(unsigned char).
如果T = unsigned char,我基本上想要省略operator =(unsigned char)。
本文似乎提供了一种方法: http://www.drdobbs.com/function-overloading-based-on-arbitrary/184401659
但是因为我不想改变我的回归类型而很难跟随它。
我通常使用TStream:
TStream<unsigned byte> ByteStream;
ByteStream+= int
ByteStream+= char
...等,我以相同的方式重载+ =。我推断出来的大小并将其转换为T.我这样做是为了避免为简单的POD案例传递void *和length参数。
答案 0 :(得分:2)
有一种简单的方法,也是一种合法的方式。
简单的方法是在有问题的功能上使用SFINAE。遗憾的是,由于这导致功能模板没有有效的专业化,这在技术上是一个错误的程序(不需要诊断)。所以避免这样做。
合法的方式是使用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 ) {}
}
};
然后使用它:
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; }
};
这是合法的,因为无所作为的专业化是完全可以的。
另一方面,所有模板函数必须至少具有一个有效特化的规则是相当模糊的,如果违反它,通常没有什么不好的事情发生。所以你可以使用第二个未使用的默认参数来SFINAE禁用你的方法。