Подтвердить что ты не робот

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

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

template <class T>
class MyClass {
  // ...
};
  • Оператор + =

    // In MyClass.h
    MyClass<T>& operator+=(const MyClass<T>& classObj);
    
    
    // In MyClass.cpp
    template <class T>
    MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
      // ...
      return *this;
    }
    

    Результаты этой ошибки компилятора:

    no match for 'operator+=' in 'classObj2 += classObj1'
    
  • оператор < <

    // In MyClass.h
    friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);
    
    
    // In MyClass.cpp
    template <class T>
    std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) {
        // ...
        return out;
    }
    

    Результаты в этом предупреждении компилятора:

    friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function
    

Что я здесь делаю неправильно?

4b9b3361

Ответ 1

// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);


// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
  // ...
  return *this;
}

Это неверно для шаблонов. Полный исходный код оператора должен быть во всех единицах трансляции, в которых он используется. Обычно это означает, что код встроен в заголовок.

Изменить: технически, согласно стандарту, можно экспортировать шаблоны, однако очень немногие компиляторы поддерживают его. Кроме того, вы также можете сделать это выше, если шаблон явно создан в MyClass.cpp для всех типов, которые являются T-, но на самом деле, что обычно игнорирует точку шаблона.

Больше прав: я прочитал ваш код, и ему нужна некоторая работа, например перегрузка оператора []. Кроме того, как правило, я бы делал размерную часть параметров шаблона, позволяя сбой + или + = быть пойманным во время компиляции и позволяя значимому распределению стека. Ваш класс исключений также должен основываться на std:: exception. Однако ни одна из них не связана с ошибками во время компиляции, это просто отличный код.

Ответ 2

Вам нужно сказать следующее (поскольку вы подружитесь с целым шаблоном, а не только с его специализацией, и в этом случае вам просто нужно добавить <> после operator<<):

template<typename T>
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

На самом деле, нет необходимости объявлять его как друга, если он не обращается к частным или защищенным членам. Поскольку вы просто получаете предупреждение, похоже, ваше выражение о дружбе - это не очень хорошая идея. Если вы просто хотите объявить одну специализацию в качестве друга, вы можете сделать это, как показано ниже, с передним объявлением шаблона перед вашим классом, чтобы operator<< распознавался как шаблон.

// before class definition ...
template <class T>
class MyClass;

// note that this "T" is unrelated to the T of MyClass !
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// in class definition ...
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj);

Оба выше и выше объявляют специализации в качестве друзей, но первый объявляет все специализации в качестве друзей, а второй объявляет специализацию operator<< как друга, чей T равен T класса, предоставляющего дружбу.

И в другом случае ваша декларация выглядит нормально, но обратите внимание, что вы не можете += a MyClass<T> в MyClass<U>, когда T и U являются разными типами с этим объявлением (если у вас нет неявное преобразование между этими типами). Вы можете сделать свой += шаблон участника

// In MyClass.h
template<typename U>
MyClass<T>& operator+=(const MyClass<U>& classObj);


// In MyClass.cpp
template <class T> template<typename U>
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) {
  // ...
  return *this;
}

Ответ 3

http://www.parashift.com/c++-faq-lite/template-friends.html

Это помогло мне с той же проблемой.

Soln:

  • Вперед объявите функцию друга перед определением самого класса. Для примера:

       template<typename T> class MyClass;  // pre-declare the template class itself
       template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x);
    
  • Объявите свою функцию друга в своем классе с добавлением "< > " к имени функции.

       friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x);
    

Ответ 4

Вы должны указать, что друг является функцией шаблона:

MyClass<T>& operator+=<>(const MyClass<T>& classObj);

См. this С++ FAQ Lite answer для деталей.

Ответ 5

Этот способ работает:

class A
{
    struct Wrap
    {
        A& a;
        Wrap(A& aa) aa(a) {}
        operator int() { return a.value; }
        operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    }
    Wrap operator*() { return Wrap(*this); }
};