Перегрузка операторов в шаблонах классов - PullRequest
13 голосов
/ 25 октября 2010

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

template <class T>
class MyClass {
  // ...
};
  • operator + =

    // 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'
    
  • operator << </p>

    // 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
    

Что я здесь не так делаю?

Ответы [ 5 ]

13 голосов
/ 25 октября 2010

Вам нужно сказать следующее (поскольку вы подружитесь с целым шаблоном вместо его специализации, в этом случае вам просто нужно будет добавить <> после 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;
}
10 голосов
/ 25 октября 2010
// 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.Тем не менее, ни одна из них не связана с ошибками во время компиляции, это просто не отличный код.

5 голосов
/ 01 мая 2013

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

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

Soln:

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

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

       friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x);
    
0 голосов
/ 02 августа 2013

Так работает:

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); }
};
0 голосов
/ 25 октября 2010

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

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

См. этот C ++ FAQ Lite ответ для подробностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...