嵌套模板类和全局命名空间中的函数

时间:2018-03-31 12:07:41

标签: c++ templates visual-c++ dependent-name

我正在研究一个模板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)

如果我输入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;
}

2 个答案:

答案 0 :(得分:1)

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

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

有关更多信息,请参阅here

其次,根据上述声明,当尝试在operator<<中为myGraph<T> cout << g.mGraphNodes[i] << endl;调用T时,由于non-deduced contexts)无法推断operator<<<T>(strm, g.mGraphNodes[i]); // ~~~ }:

  

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

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

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

BTW:您应该为{{1}}提供返回值。

答案 1 :(得分: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访问的周围命名空间(仅)。这对于“它只是有用”来说是个奇特的词。