具有特征的力类型定义

Force type definition with traits

本文关键字:类型 定义 特征      更新时间:2023-10-16

我写了这些表示图形的类:

class Node{
  public:
    typedef std::vector<Node>::iterator iterator;
    iterator begin() {return neigh.begin();}
    iterator end() {return neigh.end();}
  public:
    Node(std::string n) : name(n) {}
    std::string getName() {return name; }
    void addNeigh(Node n){
      neigh.push_back(n);
    } 
  private:
    std::string name;
    std::vector<Node> neigh;
};
class Map{
  public:
    typedef std::vector<Node>::iterator iterator;
    iterator begin() {return nodes.begin();}
    iterator end() {return nodes.end();}
  public:
    Map(std::string n) : map_name(n) {}
    void addNode(Node n){
      nodes.push_back(n);
    }

    std::string getName() { return map_name; }
    int getNumNodes() {return nodes.size();}
  private:
    std::string map_name;
    std::vector<Node> nodes;
};

然后我想编写一个函数printGraph,它使用特征打印一些图形信息:

template<typename T>
struct GraphTraits{
};
template<>
struct GraphTraits<Map>{
  typedef Map::iterator node_iterator;
  static node_iterator node_begin(Map map){ return map.begin();}
  static node_iterator node_end(Map map) { return map.end();}
  static std::string getName(Map m) {return m.getName();}
};
template<typename T>
void printGraph(T t){
  std::cout << std::endl 
            << "--------------------------------------" << std::endl  
            << "|             printGraph             |" << std::endl  
            << "--------------------------------------" << std::endl;
  std::cout << "Graph name: " << GraphTraits<T>::getName(t) << std::endl;
  for(GraphTraits<T>::node_iterator it = GraphTraits<T>::node_begin(t), e = GraphTraits<T>::node_end(t);
        it != e; ++it) {
          std::cout<< (*it).getName() << std::endl; }
}

如果我尝试编译此代码,则会出现以下错误:

grafo.cpp:75:37: error: expected ';' in 'for' statement specifier
  for(GraphTraits<T>::node_iterator it = GraphTraits<T>::node_begin(t), e = GraphTraits<T>::node_end(t);
                                    ^
grafo.cpp:75:37: error: use of undeclared identifier 'it'
grafo.cpp:75:73: error: use of undeclared identifier 'e'
  for(GraphTraits<T>::node_iterator it = GraphTraits<T>::node_begin(t), e = GraphTraits<T>::node_end(t);
                                                                        ^
grafo.cpp:76:9: error: use of undeclared identifier 'it'
        it != e; ++it) {
        ^
grafo.cpp:76:15: error: use of undeclared identifier 'e'
        it != e; ++it) {
              ^
grafo.cpp:76:16: error: expected ')'
        it != e; ++it) {
               ^
grafo.cpp:75:6: note: to match this '('
  for(GraphTraits<T>::node_iterator it = GraphTraits<T>::node_begin(t), e = GraphTraits<T>::node_end(t);
     ^
grafo.cpp:76:20: error: use of undeclared identifier 'it'
        it != e; ++it) {
                   ^
grafo.cpp:75:23: error: unexpected type name 'node_iterator': expected expression
  for(GraphTraits<T>::node_iterator it = GraphTraits<T>::node_begin(t), e = GraphTraits<T>::node_end(t);
                      ^
grafo.cpp:104:3: note: in instantiation of function template specialization 'printGraph<Map>' requested here
  printGraph(mappa);
  ^

我可以解决并编译成功替换:

for(GraphTraits<T>::node_iterator....

跟:

for(GraphTraits<Map>::node_iterator....

但这printGraph失去了它的普遍性。

有人可以给我一些提示来解决问题吗?

一般来说,是否可以使用特征来强制数据类型定义?我的意思是:

template<typename T>
struct ATraits{
 -> type "iterator" must be defined
};

这样每个专业都必须定义:

typedef ..something.. iterator;

您忘记使用 typename 关键字。

GraphTraits<Map>::node_iterator中,编译器知道使用了什么特化GraphTraits,并且可以确定node_iterator是一个typedef。

GraphTraits<T>::node_iterator,它不知道将使用什么专业化,因为T还不知道。 因此,它假定node_iterator是成员变量,而不是类型。 你必须纠正这个假设。 说typename GraphTraits<T>::node_iterator

要要求GraphTraits的每个专业化都提供 typedef,您需要"概念",这些概念是为 C++11 提出的,但必须推迟到未来的版本。 所以这在今天的C++是不可能的。 但是,每当您实际使用 printGraph 时(正式地,在实例化printGraph<T>函数模板的每个模板函数实例期间),编译器都会仔细检查GraphTraits<T>::node_iterator是否真的是一种类型(因为现在它知道T并且可以执行重载解析)。