将可选迭代器传递给函数

Passing an optional iterator to a function

本文关键字:函数 迭代器      更新时间:2023-10-16

是否可以为函数定义一个可选的迭代器,根据它的存在与否来改变函数的行为?

给出一个具体的例子,考虑定义

template<typename Graph,
    typename random_access_iterator_distances,                        
    typename random_access_iterator_predecessors,                     
    typename back_insertor_iterator_frontier,                         
    typename back_insertor_iterator_explored >
    void dijkstra(const Graph &g,                                     
            const typename boost::graph_traits < Graph >::vertex_descriptor source,    
            random_access_iterator_distances   distances,             
            random_access_iterator_predecessors predecessors,         
            const typename boost::graph_traits < Graph >::vertex_descriptor target = -1,
            back_inserter_iterator_frontier frontier = null_iterator,                 
            back_inserter_iterator_explored explored = null_iterator );

其中null_iterator是表示用户不想要此输出的某个值。

通过定义两个单独的函数来解决这个问题,一个具有边界并在定义中探索,另一个没有边界,这不是一个好的选择,因为它需要重复代码(因为函数中的逻辑与frontierexplored是否存在紧密耦合)。

是否有某种模式或替代null_iterator使这种类型的代码在c++中实现?

最简单的解决方案是编写一个简单的DevNullIterator。因为它的operator*不做任何事情,它被简单地内联并编译掉了。

struct DevNull {
  template<typename T> operator=(T const&) { }
  template<typename T> operator T&() { static T dummy; return dummy; }
};
struct DevNullIterator {
  DevNull operator*() const { return DevNull();}
  DevNullIterator operator++() const { return *this; }
};

是否有可能为函数定义一个可选的迭代器,根据它的存在与否来改变函数的行为?

。这是不可能的。有两个候选人;

  1. 重载。重载创建了一个新的函数(具有相同的名称),所以这不能满足您的需求。
  2. 默认参数。没有办法区分参数是来自函数的用户还是来自默认值。

感谢KeresSB注释,我最终提出了我认为是一个干净的解决方案。基本上,我使用以下模式:

typedef struct _undefinded {
}undefined_t;
template<typename Graph,
    typename random_access_iterator_distances,
    typename random_access_iterator_predecessors,
    typename back_inserter_iterator_frontier = undefined_t,
    typename back_inserter_iterator_explored = undefined_t >
    void dijkstra(const Graph &g,
            const typename boost::graph_traits < Graph >::vertex_descriptor source,
            random_access_iterator_distances   distances,
            random_access_iterator_predecessors predecessors,
            const typename boost::graph_traits < Graph >::vertex_descriptor target = -1,
            boost::optional<back_inserter_iterator_frontier> frontier = boost::optional<back_inserter_iterator_frontier>(),
            boost::optional<back_inserter_iterator_explored> explored = boost::optional<back_inserter_iterator_explored>() );

然后在函数的代码中,可以检查frontierexplored是否用

定义
        if ( frontier.is_initialized() ) {
        } else {
            std::cout << "frontier is uninitialized!" << std::endl;   
        }
        if ( explored.is_initialized() ) {
        } else {
            std::cout << "explored is uninitialized!" << std::endl;   
        }