如何将迭代器推广到某种类型

时间:2013-03-20 21:55:38

标签: c++ templates generics iterator containers

考虑这两个函数,它们适用于std :: vector:

  int connectNode(GraphNode const& newNode,std::vector<GraphNode const*>::const_iterator beginCandidates, std::vector<GraphNode const*>::const_iterator endCandidates){
    int connections =0;
    for (auto iter= beginCandidates; iter!=  endCandidates; ++iter) {
      if(connectNodes(newNode,**iter)) ++connections;
    }
    return connections;
  }

  int connectNode(GraphNode const& newNode,std::vector<GraphNode>::const_iterator beginCandidates, std::vector<GraphNode>::const_iterator endCandidates){
    int connections =0;
    for (auto iter= beginCandidates; iter!=  endCandidates; ++iter) {
      if(connectNodes(newNode,*iter)) ++connections;
    }
    return connections;
  }

这些功能适用于载体,但显然不适用于任何其他容器,例如一套。他们怎么可能被推广。我能想到的唯一可能的解决方案是使用一些非常难看的enable_if解决方法。有直接的解决方案吗? 编辑: 为了更清楚:我想要两个函数,一个用于普通容器,一个用于指针容器。真正的逻辑发生在connetNodes中,它接受两个引用。 (注意第一个函数中的**)

2 个答案:

答案 0 :(得分:2)

将迭代器作为模板参数,然后您不必担心要迭代的容器类型。

template<class T, class Iter>
int connectNode( GraphNode const& newNode, 
                 Iter beginCandidates, 
                 Iter endCandidates )
{
  // ...
}

我没有看到函数模板中任何地方使用的其他模板参数(T),但我假设您的真实代码在某处使用它。

此外,您可以static_assert使用GraphNode const*

将迭代器指向std::iterator_traits<Iter>::value_type
static_assert( std::is_same< typename std::iterator_traits<Iter>::value_type
                             GraphNode const *>::value,
               "Iterator must point to 'GraphNode const *'" );

修改

为了能够接受指向GraphNodeGraphNode const *的迭代器,使函数模板签名保持不变,但为调用connectNodes的帮助程序创建2个重载

bool do_connectNodes( GraphNode const& newNode, GraphNode const *p )
{
  return connectNodes( newNode, *p );
}

bool do_connectNodes( GraphNode const& newNode, GraphNode& n )
{
  return connectNodes( newNode, n );
}

现在,在connectNode内将if条件更改为

if( do_connectNodes(newNode,*iter) ) ++connections;

并根据迭代器指向的内容选择正确的重载。

答案 1 :(得分:2)

如前所述,使迭代器类型成为模板参数 - 这解决了泛化迭代器本身的问题。对于普通GraphNode值及其指针之间的差异,您可以使用重载:

template<class T>
T& maybe_deref(T& v){ return v; }

template<class T>
T& maybe_deref(T* p){ return *p; }

然后在connectNodes(newNode, maybe_deref(*iter))中调用它。