183

I had a perception that, type of a lambda is a function pointer. When I performed following test, I found it to be wrong (demo).

#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
    long (*pFptr)(int) = LAMBDA;  // ok
    auto pAuto = LAMBDA;  // ok
    assert(typeid(pFptr) == typeid(pAuto));  // assertion fails !
}

Is above code missing any point? If not then, what is the typeof a lambda expression when deduced with auto keyword ?

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
iammilind
  • 68,093
  • 33
  • 169
  • 336

9 Answers9

188

The type of a lambda expression is unspecified.

But they are generally mere syntactic sugar for functors. A lambda is translated directly into a functor. Anything inside the [] are turned into constructor parameters and members of the functor object, and the parameters inside () are turned into parameters for the functor's operator().

A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer (MSVC2010 doesn't support this, if that's your compiler, but this conversion is part of the standard).

But the actual type of the lambda isn't a function pointer. It's some unspecified functor type.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • 1
    MSVC2010 doesn't support conversion to function pointer, but MSVC11 does. http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx – KindDragon Oct 31 '11 at 17:04
  • 24
    +1 for "mere syntactic sugar for functors." Much potential confusion can be avoided by remembering this. – Ben Oct 31 '11 at 19:13
  • 8
    a functor is anything with `operator()` basically https://stackoverflow.com/questions/356950/c-functors-and-their-uses – TankorSmash Feb 05 '18 at 04:24
140

It is a unique unnamed structure that overloads the function call operator. Every instance of a lambda introduces a new type.

In the special case of a non-capturing lambda, the structure in addition has an implicit conversion to a function pointer.

avakar
  • 32,009
  • 9
  • 68
  • 103
  • 5
    Nice answer. Much more precise than mine. +1 :) – jalf Oct 31 '11 at 09:17
  • 4
    +1 for the unicity part, it's very surprising at first and merit attention. – Matthieu M. Oct 31 '11 at 09:41
  • Not that it really matters, but is the type really unnamed, or is it just not given a name until compilation time? IOW, could one use RTTI to find the name the compiler decided upon? – Ben Oct 31 '11 at 19:17
  • 3
    @Ben, it is unnamed and as far as the C++ language is concerned, there is no such thing as "a name the compiler decides upon". The result of `type_info::name()` is implementation-defined, so it may return anything. In practice, the compiler will name the type for the sake of the linker. – avakar Oct 31 '11 at 19:46
  • 2
    Lately, when asked this question, I usually say that the lambda's type _has_ a name, the compiler knows it, it's just unutterable. – Andre Kostur Feb 28 '18 at 06:00
33

[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [..]

The clause goes on to list varying properties of this type. Here are some highlights:

[C++11: 5.1.2/5]: The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing-return-type respectively. [..]

[C++11: 5.1.2/6]: The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

The consequence of this final passage is that, if you used a conversion, you would be able to assign LAMBDA to pFptr.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
8
#include <iostream>
#include <typeinfo>

#define LAMBDA [] (int i)->long { return 0l; }
int main ()
{
  long (*pFptr)(int) = LAMBDA;  // ok
  auto pAuto = LAMBDA;  // ok

  std::cout<<typeid( *pAuto ).name() << std::endl;
  std::cout<<typeid( *pFptr ).name() << std::endl;

  std::cout<<typeid( pAuto ).name() << std::endl;
  std::cout<<typeid( pFptr ).name() << std::endl;
}

The function types are indeed same, but the lambda introduces new type (like a functor).

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • I recommend [the CXXABI unmangling approach](https://stackoverflow.com/questions/281818/unmangling-the-result-of-stdtype-infoname) if you're already going this route. Instead, I usually make use of `__PRETTY_FUNCTION__`, as in `template const char* pretty(T && t) { return __PRETTY_FUNCTION__; }`, and strip off the extra if it starts to get crowded. I prefer to see the steps shown in template substitution. If you're missing `__PRETTY_FUNCTION__`, there are alternatives for MSVC, etc., but the results are always compiler-dependent for the same reason CXXABI is necessary. – John P Jun 06 '18 at 05:20
1

It should also note that lambda is convertible to function pointer. However typeid<> returns a non-trvial object which should differ from lambda to generic function pointer. So the test for typeid<> is not a valid assumption. In general C++11 do not want us to worry about type specification, all that matter if a given type is convertible to a target type.

  • That's fair, but printing types goes a long way toward getting to the correct type, not to mention catching the cases where the type is convertible but doesn't satisfy other constraints. (I would always push toward "reifying" constraints wherever possible, but someone trying to do so has all the more reason to show their work during development.) – John P Jun 06 '18 at 05:26
0

To further improve jalf's answer

A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer

for example:

  typedef int (*Foo)(int a);

  auto bar = [](int a){
    return a;
  };

  int tmp = 1;

  auto bar2 = [tmp](int a){
    return a+tmp;
  };

  Foo foo = bar; // this is ok
  Foo foo2 = bar2; // this gives C/C++(413)
numan
  • 71
  • 1
  • 4
0

This is a detailed explanation about Gabriel's answer:

The Lambda function can be stored in a variable with type function<OutType<InType...>> as long as the header "functional" is included.

#include <iostream>
#include <functional> // <- Required here.
using namespace std;

void put_until_bound(int start, int bound, int dx) {
    function<bool(int)> margin;
        // The value ``margin'' will be determined by the if branches...
    if (dx > 0)             //Then we'll need an upper bound...
      margin = [bound] (int n) {
                 return n >= bound;
               };
    else if (dx < 0)        // Then we'll need a lower bound...
      margin = [bound] (int n) {
                 return n <= bound;
               };
    else                    // By default bound is everywhere...
      margin = [] (int n) {
                 return true;
               };
    for (int x = start; ! margin(x); x += dx)
      cout<<x<<", ";
    cout<<endl;
  }
// ...
// Inside the main function:
    put_until_bound(10, 64, 8);     // => 10, 18, 26, 34, 42, 50, 58, 
    put_until_bound(10, -5, -2);    // => 10, 8, 6, 4, 2, 0, -2, -4, 

You should use the latest g++ with the compile command as follows:

g++ -O3 -o outfile -std=c++2a -fconcepts filename.cxx && ./outfile 
Lh Guo
  • 21
  • 3
0

A practical solution from How can I store a boost::bind object as a class member?, try boost::function<void(int)> or std::function<void(int)>.

Community
  • 1
  • 1
Gabriel
  • 2,841
  • 4
  • 33
  • 43
  • 2
    Be aware of the performance cost of this, however (a virtual function call is incurred every time the function is called). – HighCommander4 Jul 03 '12 at 00:36
-14

This might work:

    h1 {
        font-size:20px;
      }
    h2{
        font-size:18px;
      }
    p {
        font-size: 16px;
      }
    exmp{
        font-size:16px;
        color:#000077;
        /*font-style: oblique;*/
        font-family: Lucida Console;
      }
<h1>If you truly insist in defining a datatype other then auto for your lambda variable then I would recommend the following</h1>

    <h2>Step 1: </h2>
    <p>Typedef a function pointer</p>
    <exmp> typedef void(*FuncPointerType)();</exmp>
    <p>Note the empty parentheses, this will need to be the same as the arguments later of your lambda <br> Now create a function pointer as you would normaly do.</p>
<exmp>/void (**MyFunction)() = new FuncPointerType([](){});</exmp>
<p>Note that the you will have to go and manually delete the pointer as it is created on the heap<br>Finally call the function pointer, it can be called one of 2 ways:</p>
<exmp>(*(*MyFunction))();</exmp>
<p>OR</p>
<exmp>(*MyFunction)();</exmp>
<p>Note the importance that it should be returnd for a function pointer pointer to just a function pointer.</p>
Manlx
  • 1
  • 3