Jaka jest potrzeba szablonu lambda wprowadzonego w C ++ 20, skoro C ++ 14 ma już generyczną lambdę?

99

wprowadził generyczne lambdy, które umożliwiły napisanie:

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

Jest bardzo jasne, że ta ogólna lambda funcdziała tak, jak działałaby funkcja szablonowa func.

Dlaczego komisja C ++ zdecydowała się dodać składnię szablonów dla ogólnej lamdy?

coder3101
źródło
5
A jeśli potrzebujesz użyć innego typu szablonu niż dla argumentów lub typu zwracanego? A jeśli jest potrzebny wewnątrz ciała?
Jakiś programista,
Powiedziano mi, że to interesujący przypadek użycia.
Max Langhof
Zobacz to dla porównania różnych wersji lambda: modernescpp.com/index.php/more-powerful-lambdas-with-c-20
schoetbi

Odpowiedzi:

115

Lambdy generyczne w C ++ 14 to bardzo fajny sposób na wygenerowanie funktora o operator ()podobnym wyglądzie:

template <class T, class U>
auto operator()(T t, U u) const;

Ale nie tak:

template <class T>
auto operator()(T t1, T t2) const; // Same type please

Ani tak:

template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only `std::array` please

Ani w ten sposób (chociaż faktycznie jest to trochę trudne w użyciu):

template <class T>
auto operator()() const; // No deduction

Lambdy C ++ 14 są w porządku, ale C ++ 20 pozwala nam implementować te przypadki bez kłopotów.

Quentin
źródło
2
Ładnie i zwięźle. Wystarczy dodać to: pierwsze (te same typy) można rozwiązać (auto a, decltype(a) b)w C ++ 14.
Sebastian Mach
13
@SebastianMach prawie. Dzięki temu rozwiązaniu bnie jest dedukowana, a jego argument zostanie niejawnie przekonwertowany na typ azamiast.
Quentin,
32

Ponieważ możesz używać szablonów lambd w C ++ 20, możesz ograniczyć swoje typy w łatwiejszy sposób niż wyrażenie SFINAE:

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

Ta lambda będzie działać tylko z typami wektorów.

Antoine Morrier
źródło
8
Jaki jest constevalzwiązek z nową składnią? To fajne iw ogóle, ale nie rozumiem znaczenia.
StoryTeller - Unslander Monica
To bardziej informacja o tym, co C ++ 20 dodaje do wyrażenia lambda, niż odpowiedź na pytanie
Antoine Morrier
24

Propozycja , która została przyjęta do C ++ 20 ma długi odcinek motywacji, z przykładami. Założenie jest takie:

Istnieje kilka kluczowych powodów, dla których obecna składnia definiowania generycznych lambd jest uznawana przez autora za niewystarczającą. Istota tego polega na tym, że niektóre rzeczy, które można łatwo zrobić za pomocą normalnych szablonów funkcji, wymagają znacznych skoków po pętli, aby można było je wykonać za pomocą ogólnych lambd, lub nie można ich w ogóle zrobić. Autor uważa, że ​​lambdy są na tyle wartościowe, że C ++ powinien je obsługiwać równie dobrze jak zwykłe szablony funkcji.

Poniżej znajduje się kilka przykładów.

StoryTeller - Unslander Monica
źródło
21

Nowa „znana składnia szablonów” dla lambd wprowadzona w C ++ 20 sprawia, że ​​konstrukcje takie jak  for_types i są  for_range opłacalne i znacznie bardziej czytelne w porównaniu z alternatywami C ++ 17.

(źródło: iteracja w czasie kompilacji z lambdami C ++ 20 )

Inną interesującą rzeczą, którą można zrobić zarówno na generycznych lambdach C ++ 14, jak i C ++ 17, jest bezpośrednie wywołanie  operator() przez jawne przekazanie parametru szablonu:

C ++ 14:

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

C ++ 20:

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

Powyższy przykład C ++ 14 jest całkiem bezużyteczny: nie ma możliwości odniesienia się do typu podanego  operator() w treści lambdy bez podania nazwy argumentu i użycia  decltype. Dodatkowo jesteśmy zmuszeni do przekazania argumentu, nawet jeśli możemy go nie potrzebować.

Przykład C ++ 20 pokazuje, jak T jest łatwo dostępny w treści lambda i że zerową wartość lambda można teraz dowolnie określać za pomocą szablonu. Będzie to bardzo przydatne do implementacji wyżej wymienionych konstrukcji w czasie kompilacji

Hamza.S
źródło