Пропуск методов шаблона класса на основе параметра шаблона

0

Я видел, что различные инкарнации моего вопроса отвечали/отвечали тоже, но мне все еще трудно понять, как опустить функции, которые мои состояния компилятора неоднозначны.

У меня есть класс, который предназначен для обработки потоков данных. Я перегрузил операторы = и + =, чтобы класс потока мог потреблять данные других типов, переставляя его в шаблон типа 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).

Я просто хочу, чтобы оператор = (unsigned char) был опущен, если T = unsigned char.

Эта статья, как представляется, дает возможность сделать это: http://www.drdobbs.com/function-overloading-based-on-arbitrary/184401659

Но с этим трудно справиться, потому что я не хочу менять свои возвращаемые типы.

Обычно я использую TStream следующим образом:

   TStream<unsigned byte> ByteStream;
   ByteStream+= int
   ByteStream+= char

... и т.д., где я перегружаю + = таким же образом. Я выводил размер входящего и преобразовывал его в T. Я делаю это, чтобы избежать передачи void * и аргумента длины для простых случаев POD.

  • 1
    Что это? TStream::~ptiStream();
  • 0
    @BrianBi: Упс, опечатка. Я сокращал код сообщения, и это было старое имя класса шаблона. Я сделал правку, чтобы исправить это.
Показать ещё 5 комментариев
Теги:
templates
specialization

1 ответ

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 свои методы, используя второй неиспользуемый аргумент по умолчанию.

  • 0
    В последнем фрагменте у вас есть блочный template<typename T> .
  • 0
    мой кросс-компилятор не поддерживает std :: is_base_of
Показать ещё 8 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню