C++ 嵌套的模板类和全局命名空间中的函数
我正在研究一个模板图数据结构,它是GraphNode对象的STL向量。我定义了嵌套在Graph类中的GraphNode类,当我在Graph对象Visual Studio 15(C++)报告的重载插入操作符中调用GraphNode对象的重载插入操作符时C++ 嵌套的模板类和全局命名空间中的函数,c++,templates,visual-c++,dependent-name,C++,Templates,Visual C++,Dependent Name,我正在研究一个模板图数据结构,它是GraphNode对象的STL向量。我定义了嵌套在Graph类中的GraphNode类,当我在Graph对象Visual Studio 15(C++)报告的重载插入操作符中调用GraphNode对象的重载插入操作符时 (30):警告C4346:'myGraph::myGraphNode':依赖名称不是类型 (30):注:前缀为“typename”表示类型 (30):错误C2061:语法错误:标识符“myGraphNode” (33):错误C2805:二进制运算符
(30):警告C4346:'myGraph::myGraphNode':依赖名称不是类型
(30):注:前缀为“typename”表示类型
(30):错误C2061:语法错误:标识符“myGraphNode”
(33):错误C2805:二进制运算符首先,参数声明的正确语法应为
template <typename T>
ostream& operator<<(ostream& strm, const typename myGraph<T>::myGraphNode& gn)
// ~~~~~ ~~~~~~~~
但是很难看。对于您的情况,您可以只实现operator模板类型推断仅匹配模式。它不会反转依赖类型,因为(在一般情况下)这是不可能的
解决这个问题的方法是我称之为Koenig算子的技术
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
这是一个注入周围名称空间(仅)的非模板运算符,可通过ADL访问。这是“it just works”的花哨词语。问题源于这样一个事实,即当解析器遇到myGraph::myGraphNode
时,由于myGraph
是一个模板,所以它(通常)无法知道myGraphNode
是否引用类型、对象,或者不预先为某些T
实例化模板的其他内容。因此,决定将其解释为“默认”值,并且需要添加typename(如下所示:typename myGraph::myGraphNode
)要显式地告诉解析器这是一种类型。谢谢,但我想重载myGraphNode对象的插入运算符,而不是让myGraph类了解myGraphNode实现。我知道有解决这个问题的办法,我想更好地理解这个问题。我试图在第一个回答的链接中遵循这一技巧,但似乎很难准确理解在我的具体案例中该做什么。谢谢你的解释和指导。谢谢。这个operator@studentProgrammer那么你在理解第一期杂志时仍然有困难?(即关于使用typename
)@studentProgrammer第二期,据我所知,没有办法;您必须指定模板参数,如operator。当我按照您的建议执行typename时,仍然会出现编译器错误。谢谢Yakk,这同样有效。我试图将函数的实现排除在定义之外,因为有些函数变得相当长。有没有可能把这项计划付诸实施operator@student转到另一种方法。像void打印(std::ostream&)代码>
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)
#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<<<T>(strm, g.mGraphNodes[i]);
// ~~~
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;
}
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
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