Я работаю над шаблоном структуры данных Graph, который является вектором STL объектов GraphNode. Я определил класс GraphNode, вложенный в класс Graph, и когда я вызываю перегруженный оператор вставки для объекта GraphNode внутри перегруженного оператора вставки для объектов Graph, отчеты Visual Studio 15 (C ++),
(30): warning C4346: 'myGraph<T>::myGraphNode': dependent name is not a type (30): note: prefix with 'typename' to indicate a type (30): error C2061: syntax error: identifier 'myGraphNode' (33): error C2805: binary 'operator <<' has too few parameters
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>::myGraphNode& gn)
добавив слово typename ко второму формальному параметру
template <typename T>
ostream& operator<<(ostream& strm, typename const myGraph<T>::myGraphNode& gn)
Компилятор генерирует следующую ошибку
(49): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const myGraph<int>::myGraphNode' (or there is no acceptable conversion)
Я получаю ту же ошибку, если у меня есть имя типа const …. или имя типа const …
Для полноты здесь весь код несколько упрощен для этого поста.
Спасибо за любую помощь
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef unsigned int uint;
template <typename T>
class myGraph {
public:
class myGraphNode {
public:
myGraphNode(T val = T());
T mData;
}; // end class myGraphNode
myGraph();
uint addGraphNode(T data);
vector<myGraphNode> mGraphNodes;
}; // end class myGraph// myGraphNode
template <typename T>
myGraph<T>::myGraphNode::myGraphNode(T val) : mData(val) {}
template <typename T>
ostream& operator<<(ostream& strm, typename const myGraph<T>::myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}// myGraph
template <typename T>
myGraph<T>::myGraph() {}
template <typename T>
uint myGraph<T>::addGraphNode(T data) {
myGraph<T>::myGraphNode node(data);
mGraphNodes.push_back(node);
}
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>& g) {
for (uint i = 0; i < g.mGraphNodes.size(); ++i)
cout << g.mGraphNodes[i] << endl;
return strm;
} // end operator<<(...)
int main()
{
myGraph<int> g;
g.addGraphNode(3);
g.addGraphNode(5);
cout << g << endl;
return 0;
}
Во-первых, правильный синтаксис для объявления параметров должен быть
template <typename T>
ostream& operator<<(ostream& strm, const typename myGraph<T>::myGraphNode& gn)
// ~~~~~ ~~~~~~~~
обращаться Вот для получения дополнительной информации.
Во-вторых, с приведенным выше объявлением, при попытке вызвать его в operator<<
за myGraph<T>
лайк cout << g.mGraphNodes[i] << endl;
, T
не может быть выведено из-за не выводимые контексты):
Спецификатор вложенного имени (все слева от оператора разрешения области: 🙂 типа, указанного с помощью квалифицированного идентификатора:
Это означает, что вы должны явно указать аргумент шаблона, например,
operator<<<T>(strm, g.mGraphNodes[i]);
// ~~~
Но это безобразно. Для вашего случая вы можете просто реализовать operator<<
за myGraph<T>
лайк
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>& g) {
for (uint i = 0; i < g.mGraphNodes.size(); ++i)
cout << g.mGraphNodes[i].mData << endl;
return strm;
}
Кстати: вы должны дать возвращаемое значение для myGraph<T>::addGraphNode
,
Вывод типа шаблона соответствует только шаблонам. Он не инвертирует зависимые типы, потому что это (в общем случае) невозможно.
Способ решения этой проблемы — техника, которую я называю операторами Кенига.
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
Поместите это в тело myGraphNode
,
class myGraphNode {
public:
myGraphNode(T val = T());
T mData;
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
}; // end class myGraphNode
Это не шаблонный оператор, внедряемый в окружающее пространство имен (только), доступное через ADL. Какие красивые слова для «это просто работает».