2

我正在研究模板 Graph 数据结构,它是 GraphNode 对象的 STL 向量。我定义了嵌套在 Graph 类中的 GraphNode 类,当我在 Graph 对象 Visual Studio 15 (C++) 报告的重载插入运算符内调用 GraphNode 对象的重载插入运算符时,

(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)

如果我 typename const .... 或 const typename ... 我会得到同样的错误

为了完整起见,这里的所有代码都为这篇文章做了一些简化。谢谢你的帮助

#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;
}
4

2 回答 2

1

首先,参数声明的正确语法应该是

template <typename T>
ostream& operator<<(ostream& strm, const typename myGraph<T>::myGraphNode& gn)
//                                 ~~~~~ ~~~~~~~~

请参阅此处了解更多信息。

其次,使用上述声明,当尝试将其调用operator<<myGraph<T>likecout << g.mGraphNodes[i] << endl;时,T由于未推断上下文而无法推断)

使用限定 ID 指定的类型的嵌套名称说明符(范围解析运算符 :: 左侧的所有内容):

这意味着,您必须为其明确指定模板参数,例如

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.

于 2018-03-31T12:23:01.943 回答
1

模板类型推导只匹配模式。它不会反转依赖类型,因为(在一般情况下)这是不可能的。

解决这个问题的方法是一种我称之为 Koenig 算子的技术。

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 访问的非模板运算符。这是“它只是工作”的花哨词。

于 2018-03-31T13:13:10.983 回答