简体   繁体   English

将可选的迭代器传递给函数

[英]Passing an optional iterator to a function

Is it possible to define an optional iterator to a function that will change the behaviour of the function based on its presence or not? 是否可以为函数定义一个可选的迭代器,该迭代器将根据函数的存在与否更改其行为?

To give a concrete example consider the definition 举一个具体的例子,考虑一下定义

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 );

Where the null_iterator would be some value that indicates the user does not want this output. null_iterator是某个值,该值指示用户不需要此输出。

The work-around for this by defining two separate functions, one with frontier and explored in the definition, another without it, would not be a good alternative, because it would require duplication of code (since the logic in the function is tightly coupled with whether either frontier or explored is present.) 为此,通过定义两个独立的函数(一个具有边界并在定义中进行了探索,另一个没有该函数)的解决方法将不是一个很好的选择,因为它将需要重复代码(因为该函数中的逻辑与是否存在frontier或已explored 。)

Is there somekind of pattern or replacement of null_iterator to make this type of code realizable in C++? 是否有somekind的模式或替代的null_iterator要在C ++这种类型的代码实现的呢?

The easiest solution is to write a simple DevNullIterator. 最简单的解决方案是编写一个简单的DevNullIterator。 Since it's operator* doesn't do anything, it's trivially inlined and compiles away. 由于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; }
};

Is it possible to define an optional iterator to a function that will change the behaviour of the function based on its presence or not? 是否可以为函数定义一个可选的迭代器,该迭代器将根据函数的存在与否更改其行为?

No. This is not possible. 不可以。 There are two candidates; 有两个候选人;

  1. Overloading. 重载。 Overloading creates a new function (with the same name), so this does not meet your needs. 重载会创建一个新函数(具有相同的名称),因此这不能满足您的需求。
  2. Default arguments. 默认参数。 There is no way to distinguish whether an argument comes from the user of the function or from the default. 无法区分参数是来自函数的用户还是默认值。

Thanks to KeresSB comment, I ended up coming up with what I think is a clean solution. 感谢KeresSB的评论,我最终提出了我认为是干净的解决方案。 Essentially, I use the following pattern: 本质上,我使用以下模式:

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>() );

Then inside the code of the function, it is possible to check if either frontier or explored are defined with 然后该函数的代码的内部,也能够检查是否任一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;   
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM