66

What's the notation for declaring a lambda variable, or function parameter, without the use of auto or templates? Is there any way to do so? Or does the compiler define a unique class object for each lambda whose name is unknown to the programmer before compile time? If so, why? Can't they just be passed as some sort of function pointer? It would be a major disappointment if that were not possible.

2
  • 1
    "It would be a major disappointment if that were not possible." Why? How could that possibly be useful? Commented Nov 14, 2011 at 19:33
  • @ildjarn For runtime lambda! Commented Feb 18, 2013 at 1:42

4 Answers 4

62

Lambdas may hold state (like captured references from the surrounding context); if they don't, they can be stored in a function pointer. If they do, they have to be stored as a function object (because there is no where to keep state in a function pointer).

// No state, can be a function pointer:
int (*func_pointer) (int) = [](int a) { return a; };

// One with state:
int b = 3;
std::function<int (int)> func_obj = [&](int a) { return a*b; };
Sign up to request clarification or add additional context in comments.

5 Comments

Oh, I get it. So that's why they're of undetermined type, because they could be a function object with a few member variables?
I suspect having an indeterminate type is more a C++ standard thing; IIRC, most of the literals in c++ don't actually have a defined "type", rather, they are a literal that can convert to different types (like, a string literal is not a const char *. It can become a const char * or a char *). I suspect this gives implementations some leeway? But certainly one of the benefits of this is it allows a literal to become multiple types. (some of this is on shaky memories of the standard though, so reader bewarned)
Actually a string literal is a const char[N] where N is the number of characters in it plus one.
The second solution does seem to violate the "without templates" part of the question. That's unavoidable, though: the type of a lambda cannot be named, so you either have to use a standard conversion to another type or use templates. (User-defined, non-template conversions can't name the lambda source type either). So, as it happens the only conversion from lambda types that does not involve templates is to a function pointer.
@MSalters it depends whether you consider "using a template defined in std" as "with templates" or not. Remember that std::string is an alias for std::basic_string<char>
26

You can use a polymorphic wrapper for a function object. For example:

#include <functional>

std::function<double (double, double)> f = [](double a, double b) { return a*b };

Comments

0

What's the notation for declaring a lambda variable, or function parameter, without the use of auto or templates?

You could rely on the fact that capture-less lambdas are convertible to function pointers, like this:

void(*f)() = [] { };

If the lambda captures anything, you can also store it in std::function or the better, modern alternatives std::copyable_function and std::move_only_function.

Or does the compiler define a unique class object for each lambda whose name is unknown to the programmer before compile time?

Yes, this happens no matter what. Every lambda expression has a closure type by definition, which is a "unique, unnamed non-union class type". It's simply how lambda expressions work; the fact that they're actually of class type with some call operator makes it possible to store captures in the lambda, which is something a function pointer cannot do.

A capture-less lambda could theoretically result in a function pointer directly instead of being convertible to one (see [expr.prim.lambda.closure] p9), but this would make lambdas with/without captures behave in a radically different way, and that would be confusing and annoying.

Comments

0

No, the type of each lambda is unique and unnamed, so there's nothing you could replace auto with without at least some change in semantics.

std::function (and other std::..._function classes) have overhead, only use them if you need the ability to select one of several lambdas at runtime.

Function pointers should have no overhead, but can only point to capture-less lambdas, as explained in the other answers.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.