Дружественная функция для шаблонного класса

При работе в С++ время от времени приходится создавать свои собственные шаблоны. Их синтаксис описывается в любой более-менее приличной книге по С++. Но правильное объявление дружественной функции может вызвать трудности. Рассмотрим шаблонный класс.

template <class T> class MyClass
{
  T value_;

public:
  MyClass(const T &value) : value_(value) {};
  
  MyClass<T> copy() const { return *this;};
  
  friend bool operator == (const MyClass<T>&, const MyClass<T>&);
};

//Сама дружественная функция
template <class T> bool operator == (const MyClass<T> &left,
                                     const MyClass<T> &right)
{
  return (left.value_ == right.value_);
}

Вроде бы все легально. Но при попытке его скомпилировать мы получим сообщение (компилятор g++):

main.cpp:15:66: warning: friend declaration ‘bool operator==(const MyClass<T>&, const MyClass<T>&)’ declares a non-template function [-Wnon-template-friend]
friend bool operator == (const MyClass<T>&, const MyClass<T>&);

g++ ругается на то, что дружественная функция объявлена не как шаблон. Для исправления этого недостатка, объявление класса MyClass нужно переписать так:

template <class T> class MyClass
{
  T value_;

public:
  MyClass(const T &value) : value_(value) {};
  
  MyClass<T> copy() const { return *this;};

  template <class V>
    friend bool operator == (const MyClass<V>&,
                             const MyClass<V>&);
};

Теперь все нормально компилируется. Это предпочтительный вариант решения проблемы, но есть и другой.

template <class T> class MyClass
{
  T value_;

public:
  MyClass(const T &value) : value_(value) {};
  
  MyClass<T> copy() const { return *this;};

  friend bool operator == (const MyClass<T> &left,
                           const MyClass<T> &right)
  {
    return (left.value_ == right.value_);
  };
};

В данном случае тело функции располагается в месте ее объявления. А как насчет методов класса? В нашем примере тело метода располагается внутри объявления класса. Если бы мы захотели его вынести, нужно было бы написать так:

template <class T> class MyClass
{
  T value_;

public:
  MyClass(const T &value) : value_(value) {};
  
  MyClass<T> copy() const;

  template <class V>
    friend bool operator == (const MyClass<V>&,
                             const MyClass<V>&);
  
};

template <class T> MyClass<T> MyClass<T> :: copy() const
{
  return *this;
}

Обратите внимание: при объявлении области видимости класса MyClass<T> ключевое слово typename не нужно.

Добавить комментарий

Ваш адрес email не будет опубликован.