Сбой вывода параметров шаблона - PullRequest
0 голосов
/ 10 ноября 2018

Рассмотрим следующий код:

template<class T>
vector<T> filter(typename vector<T>::iterator begin,
          typename vector<T>::iterator end,
          bool (*cond)(T a))
{
    vector<T> vec;
    for (typename vector<T>::iterator it = begin; it != end; it++) {
        if (cond(*it)) {
            vec.push_back(*it);
        }
    }
    return vec;
}

vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter<int>(vec.begin(), vec.end(), [](int a) {return a > 5; });

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

filter(vec.begin(), vec.end(), [](int a) {return a > 5; });

Мой вопрос: почему? компилятор может вывести тип как из лямбда-выражения, так и из итератора.

Я получаю ошибку:

Ошибка C2784 'std :: vector> фильтр (вектор> :: итератор, вектор> :: итератор, BOOL (__cdecl *) (T)) ': не удалось вывести аргумент шаблона для' bool (__cdecl *) (T) 'из 'main ::' пример c: \ users \ danii \ documents \ visual студия 2017 \ projects \ example \ example \ source.cpp 24

Я не смог найти подробности об этой проблеме. Я думаю, компилятор не может выводить внутренние типы? (например, невозможно вывести int из vector ). Если это так, то почему? если нет, то в чем дело? есть ли способ это исправить?

Еще одна вещь, с которой я столкнулся, это использование самого итератора в качестве шаблона, то есть что-то вроде

template <class T, class iter, class cond>
vector<T> filter(iter begin, iter end, cond c)

Это правильное программирование? Этот код кажется мне немного подозрительным.

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

Это потому, что лямбда-тип не совсем соответствует ожидаемому типу функции, поэтому вывод шаблона не будет работать. Компилятор не может выполнять неявное преобразование и вывод шаблона одновременно. Это будет, если вы используете функцию:

bool f(int a) {
    return a > 5;
}

int main() {
    vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
    auto another_vec = filter(vec.begin(), vec.end(), f); 
    return 0;
}
0 голосов
/ 10 ноября 2018

Полагаю, компилятор не может выводить внутренние типы? (например, не может вывести int из вектора).

Да. Это относится к невыбранным контекстам :

В следующих случаях типы, шаблоны и нетиповые значения, которые используются для создания P не участвуют в аргументе шаблона вычет, но вместо этого используйте аргументы шаблона, которые были либо выведено в другом месте или явно указано. Если параметр шаблона используется только в не выведенных контекстах и ​​явно не указано, Сбой вывода аргумента шаблона.

1) Спецификатор вложенного имени (все слева от области видимости Оператор разрешения: :) типа, указанного с помощью Квалифицированный-ID:

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

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

Тогда здесь не удается вывести тип.

Ваша идея исправить - хорошая идея, но вам не нужен параметр шаблона T, который не может (и не должен) выводиться. Вы можете изменить его на:

template<class iter, class cond>
auto filter(iter begin, iter end, cond c)
{
    vector<typename std::iterator_traits<iter>::value_type> vec;
    for (auto it = begin; it != end; it++) {
        if (cond(*it)) {
            vec.push_back(*it);
        }
    }
    return vec;
}
...