C++ 将可选迭代器传递给函数

C++ 将可选迭代器传递给函数,c++,optional-parameters,optional-arguments,C++,Optional Parameters,Optional Arguments,是否可以为函数定义一个可选迭代器,该迭代器将根据函数的存在与否改变函数的行为 给出一个具体的例子,考虑定义 template<typename Graph, typename random_access_iterator_distances, typename random_access_iterator_predecessors, typename back_insertor

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

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

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 );
模板
void dijkstra(常数图和g),
const typename boost::graph_traits::顶点描述符源,
随机访问迭代器距离,
随机访问迭代器,
const typename boost::graph_traits::顶点描述符目标=-1,
back\u inserter\u iterator\u frontier=null\u iterator,
back\u inserter\u iterator\u explored=null\u iterator);
其中,
null_迭代器
是表示用户不希望此输出的某个值

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


< > C++中的“代码> Null迭代器< /代码>是否有某种模式或替换,使这类代码在C++中实现?

< P>最简单的解决方案是编写一个简单的DevNullIterator。因为它是
操作符*
不做任何事情,所以它只是简单的内联和编译

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; }
};
struct DevNull{
模板运算符=(T常量&){}
模板运算符T&({static T dummy;return dummy;}
};
结构DevNullIterator{
DevNull运算符*()常量{return DevNull();}
DevNullIterator运算符++()常量{return*this;}
};
是否可以为函数定义一个可选迭代器,该迭代器将根据函数的存在与否改变函数的行为

不,这是不可能的。有两名候选人

  • 超载。重载会创建一个新函数(同名),因此这不能满足您的需要
  • 默认参数。无法区分参数是来自函数的用户还是来自默认值

  • 多亏了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>() );
    

    一个
    boost::optional
    怎么样?@KerrekSB:你能详细说明一下吗,这看起来是一个很有希望的解决方案?好吧,让函数参数成为
    boost::optional
    ,可能是默认的,然后,函数可以检查迭代器是否已传递。然后,一些算法可能能够通过对类型
    DevNullIterator
    的模板专门化进一步优化,例如,跳过一些只需要填充该参数输出的函数调用。第一个typedef是C-ism。
            if ( frontier.is_initialized() ) {
            } else {
                std::cout << "frontier is uninitialized!" << std::endl;   
            }
            if ( explored.is_initialized() ) {
            } else {
                std::cout << "explored is uninitialized!" << std::endl;   
            }