2013-06-06 5 views
0

Возможно ли определить необязательный итератор для функции, которая изменит поведение функции на основе ее наличия или нет?Передача необязательного итератора функции

Чтобы дать конкретный пример рассмотрим определение

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 будет какая-то значение, которое указывает пользователю не хочет этот вывод.

Обход для этого путем определения двух отдельных функций, один с границей и исследованных в определении, другой без него, не будет хорошей альтернативой, поскольку это потребует дублирования кода (поскольку логика в функции тесно связана с ли либо frontier или explored присутствует.)

есть somekind рисунка или замены null_iterator, чтобы сделать этот тип кода, реализуемый в C++?

+0

Как насчет 'повышение :: опциональный '? –

+0

@KerrekSB: Можете ли вы подробнее рассказать об этом, это похоже на перспективное решение? – ldog

+0

Ну, введите аргумент функции, который является 'boost :: optional ', возможно, по умолчанию, а затем функция может проверить, прошел ли итератор или нет. –

ответ

1

Самое простое решение - написать простой 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; } 
}; 
+0

И тогда некоторые алгоритмы могут быть в состоянии дополнительно оптимизировать с помощью специализированной специализации по типу 'DevNullIterator', которая, например, пропускает некоторые вызовы функций, которые необходимы только для заполнения вывода этого аргумента. – aschepler

0

Можно определить дополнительный итератор на функцию, которая изменит поведение функции на основе его присутствии или нет?

№ Это невозможно. Есть два кандидата;

  1. Перегрузка. Перегрузка создает новую функцию (с тем же именем), поэтому это не отвечает вашим потребностям.
  2. По умолчанию аргументы. Невозможно отличить аргумент от пользователя функции или от значения по умолчанию.
0

Благодаря комментарию 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>()); 

Тогда внутри кода функции, можно проверить, либо frontier или explored определяются с

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

Первый typedef - это C-ism. – MSalters

Смежные вопросы