省略基于模板参数的类模板方法

时间:2014-02-28 19:05:29

标签: c++ templates specialization

我已经看到我的问题的各种形式也得到了回答/回复,但我仍然很难弄清楚如何省略我的编译器状态不明确的函数。

我有一个旨在处理数据流的类。我有重载=和+ =运算符,以便流类可以通过将其转换为模板类型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参数。

1 个答案:

答案 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禁用你的方法。

相关问题