Как отсортировать шаблон специализации для итераторов? - PullRequest
0 голосов
/ 30 апреля 2018

Я пишу partition функцию, и это специализация для Bidirectional и Forward Итераторов.

И я не уверен, влияет ли порядок на результат, то есть, если эти две версии разные.

первый

template< class BIter, class UnaryPredicate>
BIter __partition( BIter first,
                   BIter last,
                   UnaryPredicate pred,
                   std::bidirectional_iterator_tag);

template<typename FIter, typename UnaryPredicate>
FIter __partition(FIter first,
                  FIter last,
                  UnaryPredicate pred,
                  std::forward_iterator_tag);

template<typename FIter, typename UnaryPredicate>
FIter newton::partition(FIter first,
                        FIter last,
                        UnaryPredicate pred)
{
  return newton::__partition(first, last, pred, std::__iterator_category(first));
}

второй

template<typename FIter, typename UnaryPredicate> FIter
__partition(FIter first,
            FIter last,
            UnaryPredicate pred,
            std::forward_iterator_tag);

template< class BIter, class UnaryPredicate>
BIter __partition(BIter first,
                  BIter last,
                  UnaryPredicate pred,
                  std::bidirectional_iterator_tag);

template<typename FIter, typename UnaryPredicate>
FIter newton::partition(FIter first,
                        FIter last,
                        UnaryPredicate pred)
{
  return newton::__partition(first, last, pred, std::__iterator_category(first));
}

Я вижу, что gcc, llmv и т. Д. Используют вторую версию, но ... Я читал, что компилятор использует первую функцию, которая подходит для его прототипа.

и разве Bidirectional Iter не будет соответствовать Forward Iter, а затем использовать эту функцию вместо специализированной?

Ответы [ 3 ]

0 голосов
/ 30 апреля 2018

Я прочитал, что компилятор использует первую функцию, которая подходит для его прототипа.

Ух ты! Это не правда. Компилятор выполняет разрешение перегрузки , чтобы найти лучшего кандидата для вызова функции, независимо от того, в каком порядке они были раньше.

Теперь, конечно, если у вас есть функция прямо посередине между ними, вы не сможете вызвать вторую (при условии, что у вас нет объявления для второй), но это не случай здесь, так как две перегрузки известны везде, где вы их называете.

и разве Bidirectional Iter не будет соответствовать Forward Iter, а затем использовать эту функцию вместо специализированной?

В этом случае нет, потому что код использует технику, называемую диспетчеризацией тегов. «Теги» полностью независимы и часто являются просто пустым классом struct some_tag {}; (но не в этом случае). Если это не так, то все равно нет, потому что разрешение перегрузки все еще происходит, и хотя двунаправленный итератор может быть преобразован в прямой итератор, все еще существует перегрузка, которая не требует какого-либо преобразования, что является лучшим соответствием.

0 голосов
/ 30 апреля 2018

Я прочитал, что компилятор использует первую функцию, которая подходит для его прототипа.

Нет: он формирует набор возможных функций-кандидатов - это функции с правильным именем, которые могут соответствовать аргументам на вашем сайте вызова. Затем он решает (или пытается решить), какой из них лучше всего подходит.

Это называется разрешение перегрузки поиск имени , а также другие элементы, связанные в верхней части этой страницы).

... это не тот случай, когда Bidirectional Iter будет соответствовать Forward Iter

Сортировка.

Вы объединяете две вещи:

  1. (концептуальная) связь между категориями итераторов (BidirectionalIterator расширяет ForwardIterator и т. Д., Как в таблице здесь ) с
  2. связь между тегами категории итераторов .

То есть вы можете логически сказать, что двунаправленный итератор является ForwardIterator, и std::bidirectional_iterator_tag является -a std::forward_iterator_tag, и оба ваших перегрузки

Iter partition(Iter first, Iter last, UnaryPredicate pred,
               std::forward_iterator_tag);
Iter partition(Iter first, Iter last, UnaryPredicate pred,
               std::bidirectional_iterator_tag);

являются кандидатами, , но для двунаправленного итератора, вторая перегрузка является лучшим соответствием согласно Ранжированию неявных последовательностей преобразования раздела связанной страницы (это точное совпадение, который, как и следовало ожидать, является лучшим, что вы можете получить).

Итак, мы можем сказать более точно, что нет никакой двусмысленности между вашими двумя перегрузками.

0 голосов
/ 30 апреля 2018

Нет, порядок не имеет значения.

Если параметр категории в точности равен std::bidirectional_iterator_tag, то одна функция лучше подходит, чем функция, требующая преобразования в базовый класс.

...