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
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); // ill-formed
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()); // ill-formed: two() is not a constant expression
static_assert(add(one)(one)() == monoid(2)()); // OK
auto glambda = [](auto a) { return a; };
int (*fp)(int) = glambda;
The behavior of the conversion function of glambda above is like
that of the following conversion function:
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
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)
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); // ill-formed
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*
};
}
};