Мой вопрос несколько связан с этим вопросом: Лямбды и 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 &)>
?
Это работает, потому что тип параметра 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
becomesfunction<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
@HanXIAO В принципе. Помните, что шаблон функции - это не функция, это рецепт ее создания. Итак, как только вы выводите параметры шаблона, вы отбрасываете функцию, которая использует фактические выведенные типы. Фактически вы вызываете именно эту функцию, и поскольку она имеет реальный тип functional<bool (const int&)>
, лямбда-выражение может быть преобразовано.
Итак, он работает, потому что после создания экземпляра шаблона функции лямбда-выражение неявно преобразуется в лямбда-выражение во время фазы (этапа) перегрузки функции? Итак, процедура - это вывод параметра шаблона -> подстановка параметра шаблона -> разрешение перегрузки (где происходят преобразования?)