Передача необязательного итератора в функцию

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

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

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 настоящее.)

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

0

Решение

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

Другие решения

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

Нет, это невозможно. Есть два кандидата;

  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
По вопросам рекламы [email protected]