Я реализую словарь в C ++, используя двоичное дерево, каждый узел в моем дереве имеет ключ (int
), элемент (string
) и левый и правый дочерний элемент.
Во время этой реализации я перегрузил оператор ostream для моего BinaryTree
класса для распечатки содержимого дерева.
Кроме того, я перегрузил ostream для работы с Node
указателями, которые затем распечатали бы клавишу и элемент этого узла.
Это сработало нормально. Однако когда я попытался сделать дерево шаблоном для работы с любым типом перегрузки моего ключа или элемента, эти операторы стали более трудными.
Я выделил проблему, чтобы упростить работу, кроме того, я попытался поиграться как с узлом , так и с указателем узла , чтобы посмотреть, смогу ли я получить один к работать без другого.
Вот класс, который я создал для проверки проблемы, этот класс не шаблонизирован и работает нормально.
test.h
class myClass
{
public:
using Key = int;
myClass(Key);
friend std::ostream & operator<<(std::ostream &, const myClass &);
private:
struct Thing {
Key data;
Thing();
Thing(Key);
};
Thing* B;
Thing A;
void disp(std::ostream &) const;
friend std::ostream & operator<<(std::ostream &, myClass::Thing);
friend std::ostream & operator<<(std::ostream &, myClass::Thing *);
};
test.cpp
myClass::Thing::Thing(Key Num) { data = Num; }
myClass::myClass(Key Num)
{
A = Thing(Num); B = &A;
}
void myClass::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
std::ostream & operator<<(std::ostream & os, const myClass & c)
{
c.disp(os); return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing th)
{
os << th.data; return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing *th)
{
os << th->data; return os;
}
С помощью этого класса я могу легко создать экземпляр моего класса и std::cout
, который выдает результат, как ожидалось.
Затем превращаем этот класс в шаблон:
template <class T> class myTemplate
{
public:
using Key = T;
myTemplate(Key);
template<class A>
friend std::ostream & operator<<(std::ostream &, const myTemplate<A> &);
private:
struct Thing;
Thing A;
Thing* B;
void disp(std::ostream &) const;
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing);
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing *);
};
template <class T> struct myTemplate<T>::Thing
{
T data;
Thing() = default;
Thing(Key);
};
//Create new thing A with B a pointer to A
template <class T> myTemplate<T>::myTemplate(Key Num)
{
A = Thing(Num);
B = &A;
}
//Displays Node A & B
template <class T> void myTemplate<T>::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
template <class T> myTemplate<T>::Thing::Thing(Key Num)
{
data = Num;
}
//Overloading << will call disp function, in turn print A & B to stream
template<class T> std::ostream & operator<<(std::ostream & os, const myTemplate<T> & c)
{
c.disp(os); return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing th)
{
os << th.data; return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing *th)
{
os << th->data; return os;
}
Однако с myTemplate
, когда я пытался в main()
:
myTemplate Template(5);
cout << Template;
Код не скомпилируется, так как я получаю сообщение об ошибке:
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'const myTemplate<std::string>::Thing' (or there is no acceptable conversion)
Дополнительно комментируем строку:
os << A << std::endl;
Таким образом, только B
выводится в поток, код скомпилируется. Однако данные B
не выводятся, только адрес памяти B
.
Я заметил, что при использовании точек останова при попытке вывести B
код даже не использует определенную мной функцию перегрузки. Это не относится к классу без шаблонов, поскольку определенные мной перегрузки используются как для A
, так и для B
.
Итак, как правильно перегрузить оператор ostream для работы с элементом struct?
Извиняется за длинный вопрос, чувствовал, что я должен включить то, что я сам определил.