Почему разрешение перегрузки не выбирает первую функцию?

В следующей программе обе функции вызывают печать «Неинтегральная перегрузка», хотя у меня есть enable_if оператор, который ограничивает функцию только целочисленными типами контейнеров. Это почему?

#include <iostream>
#include <vector>
#include <type_traits>

template<bool B, typename V = void>
using enable_if = typename std::enable_if<B, V>::type;

template<typename ForwardIt>
auto f(ForwardIt first, ForwardIt)
-> enable_if<std::is_integral<decltype(*first)>{}>
{
std::cout << "Integral container type" << std::endl;
}

template<typename ForwardIt>
void f(ForwardIt, ForwardIt)
{
std::cout << "Non-integral container type" << std::endl;
}

int main()
{
struct X { };

std::vector<int> iv;
std::vector<X>   xv;

f(iv.begin(), iv.end()); // "Non-integral container type"f(xv.begin(), xv.end()); // "Non-integral container type"}

Я даже пытался использовать enable_if<!std::is_integral<...>> на второй перегрузке но безрезультатно.

5

Решение

Для типа итератора foo, decltype(*foo) будет foo::value_type&, Тип ссылки определенно не является интегральным. Вам нужно удалить ссылку (и, возможно, также cv-qualification, IIRC) перед оценкой типа с помощью std::is_integral черта, которая легко делается с std::decay черта типа преобразования:

template<bool B, typename V = void>
using enable_if = typename std::enable_if<B, V>::type;

template<typename T>
using decay = typename std::decay<T>::type;

template<typename ForwardIt>
auto f(ForwardIt first, ForwardIt)
-> enable_if<std::is_integral<decay<decltype(*first)>>{}>
{
std::cout << "Integral container type" << std::endl;
}

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

6

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

Другой ответ уже объяснил проблему, но я думаю, что есть лучшее решение.

Если вы хотите извлечь тип, на который указывает тип итератора, вы должны использовать iterator_traits. В вашем коде измените первую перегрузку на:

template<typename ForwardIt>
auto f(ForwardIt first, ForwardIt)
-> enable_if<std::is_integral<typename std::iterator_traits<ForwardIt>::value_type>{}>
{
std::cout << "Integral container type" << std::endl;
}

и использовать то же самое с дополнительным ! На втором. Это более наглядно, так как код достаточно ясно показывает, что он делает.

Живой пример

8

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector