auto glambda = [](auto a, auto&& b) { return a < b; }; bool b = glambda(3, 3.14); // OK auto vglambda = [](auto printer) { return [=](auto&& ... ts) { // OK: ts is a function parameter pack printer(std::forward<decltype(ts)>(ts)...); return [=]() { printer(ts ...); }; }; }; auto p = vglambda( [](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; } ); auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14 q(); // OK: outputs 1a3.14— end example
auto ID = [](auto a) { return a; }; static_assert(ID(3) == 3); // OK struct NonLiteral { NonLiteral(int n) : n(n) { } int n; }; static_assert(ID(NonLiteral{3}).n == 3); // error— end example
auto monoid = [](auto v) { return [=] { return v; }; }; auto add = [](auto m1) constexpr { auto ret = m1(); return [=](auto m2) mutable { auto m1val = m1(); auto plus = [=](auto m2val) mutable constexpr { return m1val += m2val; }; ret = plus(m2()); return monoid(ret); }; }; constexpr auto zero = monoid(0); constexpr auto one = monoid(1); static_assert(add(one)(zero)() == one()); // OK // Since two below is not declared constexpr, an evaluation of its constexpr member function call operator // cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture) // in a constant expression. auto two = monoid(2); assert(two() == 2); // OK, not a constant expression. static_assert(add(one)(one)() == two()); // error: two() is not a constant expression static_assert(add(one)(one)() == monoid(2)()); // OK— end example
template <typename T> concept C1 = /* ... */; template <std::size_t N> concept C2 = /* ... */; template <typename A, typename B> concept C3 = /* ... */; auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)> (T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> { // T2 is constrained by a type-constraint. // T1 and T2 are constrained by a requires-clause, and // T2 and the type of a4 are constrained by a trailing requires-clause. };— end example
auto glambda = [](auto a) { return a; }; int (*fp)(int) = glambda;
struct Closure { template<class T> auto operator()(T t) const { /* ... */ } template<class T> static auto lambda_call_operator_invoker(T a) { // forwards execution to operator()(a) and therefore has // the same return type deduced /* ... */ } template<class T> using fptr_t = decltype(lambda_call_operator_invoker(declval<T>())) (*)(T); template<class T> operator fptr_t<T>() const { return &lambda_call_operator_invoker; } };
void f1(int (*)(int)) { } void f2(char (*)(int)) { } void g(int (*)(int)) { } // #1 void g(char (*)(char)) { } // #2 void h(int (*)(int)) { } // #3 void h(char (*)(int)) { } // #4 auto glambda = [](auto a) { return a; }; f1(glambda); // OK f2(glambda); // error: ID is not convertible g(glambda); // error: ambiguous h(glambda); // OK: calls #3 since it is convertible from ID int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK— end example
auto GL = [](auto a) { std::cout << a; return a; }; int (*GL_int)(int) = GL; // OK: through conversion function template GL_int(3); // OK: same as GL(3)— end example
auto Fwd = [](int (*fp)(int), auto a) { return fp(a); }; auto C = [](auto a) { return a; }; static_assert(Fwd(C,3) == 3); // OK // No specialization of the function call operator template can be constexpr (due to the local static). auto NC = [](auto a) { static int s; return a; }; static_assert(Fwd(NC,3) == 3); // error— end example
struct S1 { int x, y; int operator()(int); void f() { [=]()->int { return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y) // this has type S1* }; } };— end example