Зачем нужен шаблон лямбда, введенный в С++ 20, когда в С++ 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 легко доступен в теле лямбды и что теперь нулевая лямбда может быть произвольно задана. Это будет очень полезно для реализации вышеупомянутых конструкций во время компиляции