Лямбда-выражение и вывод шаблона для std :: function: почему это работает?

Мой вопрос несколько связан с этим вопросом: Лямбды и std :: function. Пожалуйста, прочтите этот вопрос и принятый на него ответ.

Итак, в принятом ответе говорится, что следующий код обеспечивает успешное определение параметра шаблона для лямбда-выражений, но почему?

template<class T>
struct Identity{
  typedef T type;//why this helps?
};

template<typename BaseT>
vector<BaseT> findMatches(vector<BaseT> search, 
    typename Identity<function<bool (const BaseT &)>>::type func)
{
    vector<BaseT> tmp;

    for(auto item : search)
    {
        if ( func(item) )
        {
            tmp.push_back(item);
        }
    }

    return tmp;
}

void Lambdas()
{
    vector<int> testv = { 1, 2, 3, 4, 5, 6, 7 };

    auto result = findMatches(testv, [] (const int &x) { return x % 2 == 0; });//lambda here.

    for(auto i : result)
    {
        cout << i << endl;
    }
}

int main(int argc, char* argv[])
{

    Lambdas();

    return EXIT_SUCCESS;
}

Приведенный выше код работает, но я не знаю почему. Во-первых, я знаю, что выведение BaseT из шаблона не происходит для лямбда, потому что это невыводимый контекст (Identify<function<bool (const BaseT &)>>::type). Вместо этого BaseT выводится из testv как int, а замена параметров шаблона происходит в Identity<function<bool (const BaseT &)>>::type.

Но что дальше? после замены Identity<function<bool (const BaseT &)>>::type становится function<bool (const BaseT &)>, но не является ли лямбда-выражение не этого типа, и преобразование не происходит при выводе параметра шаблона (хотя здесь происходит подстановка параметра шаблона)?

Спасибо за объяснение! P.S. Кажется, я знаю, что компилятор генерирует класс с уникальным именем для каждого лямбда-выражения. Так почему лямбда может совпадать с function<bool (const BaseT &)>?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Следовательно, происходит то, что BaseT выводится для параметра search, и де-факто становится известен тип для func, который зависит от BaseT. В конце концов, ваша лямбда может быть неявно преобразована в желаемый тип std::function<bool(int const&)>.

Если вы пропустите этот трюк, чтобы сделать тип func зависимым от BaseT, например:

template<typename BaseT>
vector<BaseT> findMatches(vector<BaseT> search, 
     function<bool (const BaseT &)> func)

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

Ответ принят как подходящий

But what's next? after substitution, Identity<function<bool (const BaseT &)>>::type becomes function<bool (const BaseT &)>, but isn't lambda expression not of that type, and conversions does not happen in template parameter deduction(although here is template parameter substitution)?

Вы правы, что при выводе аргумента шаблона подстановки нет, но как только это будет выполнено, мы будем рассматривать вызов функции как вызов созданной функции. Это означает, что Identity<function<bool (const BaseT &)>>::type был заменен на function<bool (const BaseT &)>, ваша инстанцированная функция, которую вы вызываете:

vector<int> findMatches(vector<int> search, function<bool (const int&)> func)

Поскольку он принимает конкретный function<bool (const int&)>, лямбда может использоваться для построения func

Итак, он работает, потому что после создания экземпляра шаблона функции лямбда-выражение неявно преобразуется в лямбда-выражение во время фазы (этапа) перегрузки функции? Итак, процедура - это вывод параметра шаблона -> подстановка параметра шаблона -> разрешение перегрузки (где происходят преобразования?)

Han XIAO 10.08.2018 15:10

@HanXIAO В принципе. Помните, что шаблон функции - это не функция, это рецепт ее создания. Итак, как только вы выводите параметры шаблона, вы отбрасываете функцию, которая использует фактические выведенные типы. Фактически вы вызываете именно эту функцию, и поскольку она имеет реальный тип functional<bool (const int&)>, лямбда-выражение может быть преобразовано.

NathanOliver 10.08.2018 15:15

Другие вопросы по теме