Сравнение в C ++ между двумя экземплярами одного шаблона класса - PullRequest
1 голос
/ 20 августа 2010

Я пытаюсь написать шаблон класса, который предоставляет оператор сравнения между двумя установками с различными типами шаблонов.Как это часто бывает, этот оператор не является другом.Ниже приведен упрощенный пример того, чего я пытаюсь достичь.

template<typename T>
class Wrapper {
  // Base type, which must have a val() method to allow comparison
  T t_;
public:
  Wrapper(const T& t) : t_(t) {}

  // Comparison operator
  template<typename B>
  friend
  bool
  operator==(const Wrapper &a, const Wrapper<B>&b) {
    return a.t_.val()==b.t_.val();
  }
};

// First example type for Wrapper
class X {
  int x_;    
public:
  X(int x) : x_(x) {}

  int
  val() const {return x_;}
};

// Second example type for Wrapper
class Y {
  int y_;
public:
  Y(int y) : y_(y) {}

  int
  val() const {return 2*y_;}
};

int
main() {
  Wrapper<X> WX(X(4));
  Wrapper<Y> WY(Y(2));
  return WX==WY ? 1 : 0;
}

Этот пример (g ++ 4.4.0) не компилируется: вместо этого он жалуется, что y_ из Wrapper<Y> является приватными так недоступна функция друга, и я понимаю, почему.Но как я могу это исправить?Добавление дружбы в обратную функцию

  template<typename B>
  friend bool operator==(const Wrapper<B> &, const Wrapper &);

в тело шаблона класса Wrapper просто вызывает неоднозначность для компилятора.Я не хочу позволять различным установкам класса Wrapper иметь доступ к закрытым членам друг друга - я хочу ограничить доступ к этому одному оператору.Это возможно?

Мой ноутбук находится в опасности из-за того, что он не подвергся перерасходу, поэтому любые идеи будут восприняты и мной, и ноутбуком (и окном в этом отношении).

Ответы [ 2 ]

2 голосов
/ 20 августа 2010

Количество вещей:

  • Когда ваш шаблон класса создается один раз для X и один раз для Y, у вас есть два определения operator==.

  • Удалите operator== из объявления класса.

  • Обратите внимание, что friend не является членом.Следовательно, диагностика нарушения прав доступа.

Попробуйте это:

template<typename T>
class Wrapper {
  // Base type, which must have a val() method to allow comparison
  T t_;
public:
  Wrapper(const T& t) : t_(t) {}

  // Comparison operator

  template<typename A, typename B>
  friend bool
  operator==(const Wrapper<A> &a, const Wrapper<B>&b);
};

template<typename A, typename B>
  bool
  operator==(const Wrapper<A> &a, const Wrapper<B>&b) {
    return a.t_.val()==b.t_.val();
  }

// First example type for Wrapper
class X {
  int x_;    
public:
  X(int x) : x_(x) {}

  int
  val() const {return x_;}
};

// Second example type for Wrapper
class Y {
  int y_;
public:
  Y(int y) : y_(y) {}

  int
  val() const {return 2*y_;}
};

int
main() {
  Wrapper<X> WX(X(4));
  Wrapper<Y> WY(Y(2));
  return ::operator==(WX, WY) ? 1 : 0;
}

Хотя мне все еще не нравится возможность, что есть два возможных friend operator== скрывается там ...

2 голосов
/ 20 августа 2010

Мой ноутбук безопасен (на данный момент), так как перечитывание C ++ FAQ-lite помогло, хотя пример изначально не соответствовал моей собственной проблеме. Следующее делает работу, перемещая определение оператора за пределы тела класса шаблона:

template <typename T> class Wrapper;

template<typename A, typename B>
inline
bool
operator==(const Wrapper<A> &a, const Wrapper<B>&b) {return a.t_.val()==b.t_.val();}

template<typename T>
class Wrapper {
  T t_;
public:
  Wrapper(const T& t) : t_(t) {}

  template<typename A, typename B>
  friend
  bool
  operator==(const Wrapper<A> &a, const Wrapper<B>&b);
};

Буду признателен за любые более изящные или проницательные предложения.

...