Использование шаблона с указателем на лямбда-функцию - PullRequest
0 голосов
/ 30 мая 2020

Я экспериментирую с некоторыми функциями C ++ 11 и обнаружил следующее:

#include <iostream>
#include <vector>

template <class T>
void map(std::vector<T>& values, T(*func)(T)) { 
    for (int &value : values) {
        value = func(value);
    }
}

int mul2(int x) {
    return 2*x;
}

auto mul3 = [](int value) {
    return value * 3;
};

int main() {
    std::vector<int> v = { 1,2,3,4,5 };
    map(v, mul3);
    for (auto value : v) {
        std::cout << value << std::endl;
    }
}

с использованием map с mul2 работает должным образом, но когда я использую mul3 функция выдает ошибку компиляции. Я ожидал, что auto в этом случае даст мне указатель на функцию int, но, похоже, здесь не так. Кто-нибудь мог объяснить такое поведение?

Ответы [ 2 ]

3 голосов
/ 30 мая 2020

Лямбда может быть неявно преобразована в указатель на функцию, но здесь не этого. Скорее, компилятор не может вывести T, потому что преобразование лямбда-указателя в указатель на функцию не происходит во время вывода.

main.cpp:5:6: note:   template argument deduction/substitution failed:
main.cpp:21:16: note:   mismatched types 'T (*)(T)' and '<lambda(int)>'
   21 |     map(v, mul3);
      |                ^

Компилятор может установить соединение между T(*)(T) и int(*)(int) и он может установить связь между int(*)(int) и лямбда-типом, но не может установить связь между T(*)(T) и лямбда-типом.

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

// Option 1: Specifying T allows implicit conversion of the lambda to fnptr
map<int>(v, mul3);

// Option 2a: Cast of lambda to fnptr allows T to be deduced
map(v, static_cast<int(*)(int)>(mul3));

// Option 2b: Converting lambda to fnptr at mul3 initialization allows T to be deduced
int (*mul3)(int) = [](int value) {
    return value * 3;
};

Однако я бы рекомендовал исправить проблему другим способом - нет причин, по которым функция должна работать с векторами, указателями на функции и целыми числами. Почему он не может работать со связанными списками, функторами и двойниками? На самом деле нет причин ограничивать такие типы; просто позвольте им быть тем, чем они являются, и посмотрите, удастся ли создать экземпляр:

template <class TContainer, TFunction>
void map(TContainer & values, TFunction const & func) { 
    for (auto &value : values) {
        value = func(value);
    }
}
1 голос
/ 30 мая 2020

В соответствии с моим комментарием (когда вопрос был закрыт), вы можете удалить детали функции, используя шаблон функтора "pattern":

template <class T, typename Functor>
void map(std::vector<T>& values, Functor func) { 
    for (int &value : values) {
        value = func(value);
    }
}

См. Здесь полный пример: https://godbolt.org/z/fdHvAP

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...