Перегрузка операторов по шаблонам классов
У меня возникают некоторые проблемы, определяющие некоторые перегрузки операторов для классов шаблонов. Например, возьмем этот гипотетический класс.
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
Что я здесь делаю неправильно?
Ответы
Ответ 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); }
};