【问题标题】:How to generalize an iterator to a certain type如何将迭代器推广到某种类型
【发布时间】:2013-03-20 21:55:37
【问题描述】:

考虑这两个函数,它们适用于 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;
  }

这些函数适用于向量,但显然不适用于任何 otehr 容器,例如一套。怎么可能一概而论。我能想到的唯一可能的解决方案是使用一些非常丑陋的 enable_if 解决方法。有直接的解决方案吗? 编辑: 为了更清楚:我想要两个函数,一个用于普通容器,一个用于指针容器。真正的逻辑发生在 connetNodes 内部,它需要两个引用。 (注意第一个函数中的**)

【问题讨论】:

  • 您是否需要强制它必须GraphNode的迭代器?
  • @Drew Dormann:它应该是 GraphNode 或 Graphnode const*。问题是我需要值和指针。此时该类型也可以保持打开状态。

标签: c++ templates generics iterator containers


【解决方案1】:

如前所述,将迭代器类型设为模板参数 - 这解决了泛化迭代器本身的问题。对于普通 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))

【讨论】:

  • 好主意,尤其是通用的 Maybe_deref !
【解决方案2】:

把迭代器作为模板参数,那么你就不用担心你迭代的是什么类型的容器了。

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

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

另外,您可以使用std::iterator_traits&lt;Iter&gt;::value_typestatic_assert 使迭代器指向GraphNode const*

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;

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

【讨论】:

  • 不幸的是,这无济于事,因为我想同时接受值的迭代器和指针的迭代器以及指针的取消引用。
  • 是的,T 是完整功能的遗留物,只是将其删除。感谢您的关注
  • @Martin 更新为允许两种迭代器。抱歉,当我第一次阅读您的问题时,我并没有完全理解它。
  • 刚刚得到了同样的想法,在编辑之前阅读你的问题。我认为这是最干净的解决方案。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-03
  • 1970-01-01
  • 2019-08-23
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 2021-06-05
相关资源
最近更新 更多