Как известно в качестве спецификаторов типов для параметров лямбда-выражений можно использовать ключевое слово
auto, и тогда тип параметров будет выведен компилятором в момент вызова лямбда выражения с конкретными аргументами.
Например,
#include <iostream>
#include <string>
int main()
{
auto plus( []( auto l, auto r ) { return l + r; } );
std::cout << plus( 1, 2 ) << '\n';
std::cout << plus( 1.5, 2 ) << '\n';
std::cout << plus( std::string( "Hello, " ), "World!" ) << '\n';
}
Вывод программы на консоль:
3
3.5
Hello, World!
В первом вызове лямбда-выражения оба аргумента имеют тип
int и тип возвращаемого значения также имеет тип
int.
Во втором вызове лямбда-выражения первый аргумент имеет тип
double, и второй аргумент - тип
int. Тип возвращаемого значения в этом случае есть тип
double.
В третьем вызове лямбда выражения первый аргумент имеет тип
std::string, а второй аргумент - тип
const char *. Тип возвращаемого значения есть тип
std::string.
То есть используя спецификаторы
auto для описания параметров, мы создали шаблонное или обобщенное лямбда-выражение.
Но иногда требуется, чтобы, например, оба параметра (или несколько параметров) имели один и тот же тип. В этом случае уже нельзя использовать спецификатор
auto, так как это позволит указывать аргументы разных типов.
Для подобных случаев в стандарте C++ 2017 введена возможность явно указать список шаблонных параметров. Например, вышеприведенное лямбда-выражение может быть переписано следующим образом
auto plus( []<typename T>( T l, T r ) { return l + r; } );
В этом случае оба аргумента при вызове лямбда-выражения должны иметь один и тот же тип.
Рассмотрите
#include <iostream>
#include <string>
int main()
{
auto plus( []<typename T>( T l, T r ) { return l + r; } );
std::cout << plus( 1, 2 ) << '\n';
// std::cout << plus( 1.5, 2 ) << '\n';
std::cout << plus( std::string( "Hello, " ), std::string( "World!" ) ) << '\n';
// std::cout << plus( std::string( "Hello, " ), "World!" ) << '\n';
}
Вывод программы на консоль:
3
Hello, World!
Закомментированные вызовы лямбда-выражения уже не будут компилироваться.
А что если нужно создать шаблонное лямбда выражение, но которое не имеет шаблонных параметров?
Например,
auto create_vector = []<typename T>( size_t n = 0 )
{
std::vector<T> v;
v.reserve( n );
return v;
};
Как в этом случае вызвать лямбда-выражение и сообщить ему требуемый шаблонный аргумент?
Это можно сделать посредством явного вызова оператора-функции. Ниже показано, как это будет выглядеть
#include <iostream>
#include <vector>
int main()
{
auto create_vector = []<typename T>( size_t n = 0 )
{
std::vector<T> v;
v.reserve( n );
return v;
};
auto v = create_vector.operator()<int>( 10 );
std::cout << "capacity = " << v.capacity() << std::endl;
}
Вывод программы на консоль:
capacity = 10