Зачем нужен шаблон лямбда, введенный в С++ 20, когда в С++ 14 уже есть универсальная лямбда?
c++14 представил общие лямбды, которые позволили написать следующее:
auto func = [](auto a, auto b){
return a + b;
};
auto Foo = func(2, 5);
auto Bar = func("hello", "world");
Совершенно очевидно, что этот общая лямбда func
работает так же, как шаблонная функция func
будет работать.
Почему комитет C++ решил добавить синтаксис шаблона для общей лямды?
Ответы
Ответ 1
Общие лямбда-выражения С++ 14 - очень крутой способ генерировать функтор с помощью operator()
который выглядит следующим образом:
template <class T, class U>
auto operator()(T t, U u) const;
Но не так:
template <class T>
auto operator()(T t1, T t2) const; // Same type please
Ни как это:
template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only 'std::array' please
Ни как это (хотя это становится немного сложно на самом деле использовать):
template <class T>
auto operator()() const; // No deduction
С++ 14 лямбда-это хорошо, но С++ 20 позволяет нам реализовать эти случаи без хлопот.
Ответ 2
Поскольку вы можете использовать шаблонные лямбды в С++ 20, вы можете ограничить свои типы более простым способом, чем выражение SFINAE:
auto lambda = []<typename T>(std::vector<T> t){};
Эта лямбда будет работать только с векторными типами.
Ответ 3
Предложение, которое было принято в C++ 20, имеет длинный раздел мотивации с примерами. Предпосылка этого такова:
Есть несколько ключевых причин, по которым автор считает, что текущий синтаксис для определения общих лямбд является недостаточным. Суть этого в том, что некоторые вещи, которые можно легко сделать с помощью обычных шаблонов функций, требуют значительных скачков, чтобы быть выполненными с помощью общих лямбд, или не могут быть выполнены вообще. Автор считает, что лямбды достаточно ценны, чтобы C++ их поддерживал так же, как и обычные шаблоны функций.
Ниже приведено немало примеров.
Ответ 4
Новый "знакомый синтаксис шаблона" для лямбд, введенный в С++ 20, делает такие конструкции, как for_types
и for_range
жизнеспособными и более удобочитаемыми по сравнению с альтернативами С++ 17.
(источник: итерация времени компиляции с лямбдами С++ 20)
Еще одна интересная вещь, которую можно сделать как на общих лямбдах С++ 14, так и на С++ 17, - это прямой вызов operator()
путем явной передачи параметра шаблона:
С++ 14:
auto l = [](auto){ };
l.template operator()<int>(0);
С++ 20:
auto l = []<typename T>(){ };
l.template operator()<int>();
Приведенный выше пример С++ 14 совершенно бесполезен: нет способа сослаться на тип, предоставленный operator()
в теле лямбды, без указания имени аргумента и использования decltype
. Кроме того, мы вынуждены передавать аргумент, хотя он может и не понадобиться.
Пример С++ 20 показывает, как T легко доступен в теле лямбды и что теперь нулевая лямбда может быть произвольно задана. Это будет очень полезно для реализации вышеупомянутых конструкций во время компиляции