Зачем нужны лямбда-выражения шаблона, представленные в C ++ 20, если в C ++ 14 уже есть общая лямбда-выражение?

99

представили общие лямбды, которые позволили написать следующее:

auto func = [](auto a, auto b){
    return a + b;
};
auto Foo = func(2, 5);
auto Bar = func("hello", "world");

Совершенно очевидно, что эта общая лямбда funcработает так же, как и шаблонная функция func.

Почему комитет C ++ решил добавить синтаксис шаблона для общей lamda?

coder3101
источник
5
Что делать, если вам нужно использовать тип шаблона, отличный от типа аргументов или возвращаемого значения? А если это нужно внутри тела?
Какой-то чувак-программист
Мне сказали, что это интересный вариант использования.
Макс Лангхоф
См. Сравнение различных версий лямбда-
выражений

Ответы:

115

Общие лямбда-выражения C ++ 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

Лямбда-выражения C ++ 14 подходят, но C ++ 20 позволяет без проблем реализовать эти случаи.

Квентин
источник
2
Красиво и лаконично. Просто добавив это: первые (те же типы) могут быть решены (auto a, decltype(a) b)в C ++ 14.
Себастьян Мах
13
@SebastianMach почти. При этом решение bне выводится, и его аргумент будет неявно преобразован в тип aвместо.
Quentin
32

Поскольку вы можете использовать шаблонные лямбды в C ++ 20, вы можете ограничить свои типы более простым способом, чем выражение SFINAE:

auto lambda = []<typename T>(std::vector<T> t){};

Эта лямбда будет работать только с векторными типами.

Антуан Моррье
источник
8
Как это constevalсвязано с новым синтаксисом? Это круто и все такое, но я не понимаю актуальности.
StoryTeller - Unslander Моника
Это больше информация о том, что C ++ 20 добавляет к лямбда-выражению, чем ответ на вопрос,
Антуан
24

В предложении, которое было принято в C ++ 20, есть длинный раздел мотивации с примерами. Предпосылка этого такова:

Есть несколько ключевых причин, по которым текущий синтаксис для определения общих лямбда-выражений автор считает недостаточным. Суть в том, что некоторые вещи, которые могут быть легко выполнены с помощью обычных шаблонов функций, требуют значительных прыжков через обруч, которые должны выполняться с помощью общих лямбда-выражений, или не могут быть выполнены вообще. Автор считает, что лямбды достаточно ценны, чтобы C ++ их поддерживал. так же хорошо, как и обычные шаблоны функций.

После этого довольно много примеров.

Рассказчик - Незеленка Моника
источник
21

Новый «знакомый синтаксис шаблонов» для лямбда-выражений, представленный в C ++ 20, делает такие конструкции, как  for_types и,  for_range жизнеспособными и намного более удобочитаемыми по сравнению с альтернативами C ++ 17.

(Источник: итерация во время компиляции с лямбда-выражениями C ++ 20 )

Еще одна интересная вещь, которую можно сделать в общих лямбда-выражениях C ++ 14 и C ++ 17, - это прямой вызов  operator() путем явной передачи параметра шаблона:

С ++ 14:

   auto l = [](auto){ };
   l.template operator()<int>(0);

С ++ 20:

  auto l = []<typename T>(){ };
  l.template operator()<int>();

Приведенный выше пример C ++ 14 совершенно бесполезен: нет способа ссылаться на тип, предоставленный  operator() в теле лямбда-выражения, без указания имени аргумента и использования  decltype. Кроме того, мы вынуждены передавать аргумент, даже если он нам может не понадобиться.

В примере C ++ 20 показано, как легко получить доступ к T в теле лямбда-выражения и что теперь можно произвольно создавать шаблон нулевого лямбда-выражения. Это будет очень полезно для реализации вышеупомянутых конструкций времени компиляции.

Hamza.S
источник