58

I'm trying to figure out how to get the address of a lambda function within itself. Here is a sample code:

[]() {
    std::cout << "Address of this lambda function is => " << ????
}();

I know that I can capture the lambda in a variable and print the address, but I want to do it in place when this anonymous function is executing.

Is there a simpler way to do so?

ruohola
  • 21,987
  • 6
  • 62
  • 97
Daksh Gupta
  • 7,554
  • 2
  • 25
  • 36
  • 26
    Is this just for curiosity, or is there an underlying problem you need to solve? If there's an underlying problem, please ask about that directly instead of asking about one single possible solution to an (for us) unknown problem. – Some programmer dude Nov 06 '19 at 10:55
  • @Someprogrammerdude Maybe with that one could write recursive lambdas, which is not too unreasonable (IMO). One could still live without that, though. – chi Nov 06 '19 at 10:58
  • 2
    @Someprogrammerdude - This is NOT out of curiosity. Unfortunately, the explanation of complete problem would be too long for anyone to read. In a nutshell, this has something to do with a specific project I am working on and if I get the address, it would be easy for me to complete the task. – Daksh Gupta Nov 06 '19 at 11:01
  • 46
    ... effectively confirming XY-problem. – ildjarn Nov 06 '19 at 11:02
  • 3
    @Daksh I would strongly advice to rethink your problem, since this is not the way to do it. Alternatively try to make the question contained enough that you can post it as a new question. – ruohola Nov 06 '19 at 11:04
  • 2
    @ruohola - Thanks for your comment.. I know how to solve my issue but knowing address would be easier.. Thanks – Daksh Gupta Nov 06 '19 at 11:06
  • 5
    Almost all large problems can be sub-divided into smaller problems, that often can be even further sub-divided You know you have enough sub-division where each sub-problem can be summarized in a single sentence, and described in full in a single paragraph. Solve each sub-problem one by one, and when they're all solved, you have solved the original large problem. In short: [Find a simpler problem](https://ericlippert.com/2014/03/21/find-a-simpler-problem/). I suggest you try this out for this large problem. – Some programmer dude Nov 06 '19 at 11:10
  • 9
    You could replace the lambda with a manually written functor class, and then use `this`. – HolyBlackCat Nov 06 '19 at 11:10
  • 2
    Alas C++ type system is not powerful enough to allow that. – n. m. could be an AI Nov 06 '19 at 11:14
  • 29
    "Getting the address of a lamba function within itself" is the *solution*, a solution you narrowly focus on. There might be other solutions, ones that might be better. But we can't help you with that since we don't know what the real problem is. We don't even know what you will use the address for. All I'm trying to do is to help you with your actual problem. – Some programmer dude Nov 06 '19 at 11:25
  • 1
    "Getting the address" presumes there's exactly one address. Not zero, not two. AFAICT, there's no such guarantee in C++, precisely the linker only needs to generate a unique address when there's a standard-mandated reason for one. And that reason is missing here. – MSalters Nov 07 '19 at 13:49
  • 10
    @Someprogrammerdude While most of what you're saying is sensible, I don't see a problem with asking "How can *X* be done?". *X* here is "getting the address of a lambda from within itself". It doesn't matter that you don't know what the address will be used for and it doesn't matter that there might be "better" solutions, in someone else's opinion that may or may not be feasible in an unknown code base (to us). A better idea is to simply focus on the stated problem. This is either doable or it isn't. If it is, then *how*? If not, then mention it isn't and something else can be suggested, IMHO. – code_dredd Nov 07 '19 at 21:25
  • 9
    These XY problem debates are so tedious. This is a perfectly well defined question. Why do we need a debate about whether it should be asked? What's the problem with just answering it or not answering it, at one's own discretion? – N. Virgo Nov 08 '19 at 02:37
  • @Nathaniel Agreed here. XY problems are annoying for both sides, but this is a perfectly good question that is highly upvoted. I will be sorely disappointed if it ends up being closed because others feel the reasoning for posting is invalid. – jonspaceharper Nov 08 '19 at 10:03

5 Answers5

59

There is no way to directly get the address of a lambda object within a lambda prior to .

Now, as it happens this is quite often useful. The most common use is in order to recurse.

The y_combinator comes from languages where you could not talk about yourself until you where defined. It can be implemented pretty easily in :

template<class F>
struct y_combinator {
  F f;
  template<class...Args>
  decltype(auto) operator()(Args&&...args) const {
    return f( f, std::forward<Args>(args)... );
  }
  template<class...Args>
  decltype(auto) operator()(Args&&...args) {
    return f( f, std::forward<Args>(args)... );
  }
};
template<class F>
y_combinator(F)->y_combinator<F>;

now you can do this:

y_combinator{ [](auto& self)-> void {
  std::cout<<"Address of this lambda function is => "<< &self;
} }();

There are a few useful variations. One variation I find particularly useful is:

template<class F>
struct y_combinator {
  F f;
  template<class...Args>
  decltype(auto) operator()(Args&&...args) const {
    return f( *this, std::forward<Args>(args)... );
  }
  template<class...Args>
  decltype(auto) operator()(Args&&...args) {
    return f( *this, std::forward<Args>(args)... );
  }
};

where the self passed can be called without passing in self as the first argument.

The second matches the real y combinator (aka the fixed point combinator) I believe. Which you want depends on what you mean by 'address of lambda'.

There is also this pithy one:

template<class R, class...Args>
auto Y = [] (auto f) {
  auto action = [=] (auto action) -> std::function<R(Args...)> {
    return [=] (Args&&... args)->R {
      return f( action(action), std::forward<Args>(args)... );
    };
  };
  return action(action);
};

which returns a std function.


In accessing this within a lambda gets easier:

auto fib = [](this auto& self, int n) {
  if (n < 2) return n;
  return self(n-1) + self(n-2);
};

you can tag the first argument as this, and it becomes itself. It even works with the overload set trick, where self is the most-deduced type.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • 3
    wow, Y combinators are hard enough to wrap your head around in dynamic-typed languages like Lisp/Javascript/Python. I'd never thought I would see one in C++. – Jason S Nov 06 '19 at 22:25
  • 1
    Neat! That's not really a Y-combinator though, is it? It seems to be another fixpoint combinator. – leftaroundabout Nov 07 '19 at 09:37
  • 14
    I feel like if you do this in C++ you deserve to get arrested – user541686 Nov 07 '19 at 10:40
  • It appears the two solutions are virtually identical because `(void*)this->f == (void*)this` ? – MSalters Nov 07 '19 at 14:01
  • 3
    @MSalters Uncertain. If `F` is not standard layout, then `y_combinator` isn't, so the sane guarantees are not provided. – Yakk - Adam Nevraumont Nov 07 '19 at 14:05
  • Since this answer mentions recursion, note that if you just want to call the lambda recursively, see [Recursive lambda functions in C++11](https://stackoverflow.com/questions/2067988/recursive-lambda-functions-in-c11) – cartographer Nov 07 '19 at 15:35
  • 2
    @carto the top answer there only works if your lambda lives in scope, and you don't mind type erasure overhead. The 3rd answer is the y combinator. The 2nd answer is a manual ycombinator. – Yakk - Adam Nevraumont Nov 07 '19 at 16:59
  • @Yakk-AdamNevraumont Probably should have been more clear but yeah, there is the overhead and it will only allow you to call the lambda (you still wont be able to take the address, since `std::function::target` needs the lambda type), plus you can't have it be polymorphic/generic since the types need to be specified. – cartographer Nov 07 '19 at 17:06
  • If you really wanted to mess with capturing lambdas and their function pointers, [this answer](https://stackoverflow.com/a/41528436/2228299) shows how you might do it (unfortunately it's not helpful here though). – cartographer Nov 07 '19 at 17:13
  • The only thing I don't understand is the `template_name { blah }()` syntax to instantiate and use the combinator. Is this an instance of [direct-list-initialization](https://en.cppreference.com/w/cpp/language/list_initialization) (case 4)? If so, then I'm guessing that the the enclosed function is made to correspond with the template's `f` member, and that's how that template argument `F` gets deduced. – Kaz Nov 08 '19 at 01:12
  • 3
    @kaz C++17 feature. In 11/14 you'd write a make function, which would deduxe F; in 17 you can deduce with template names (and sometimes deduction guides) – Yakk - Adam Nevraumont Nov 08 '19 at 03:45
  • Doesn't compile: http://coliru.stacked-crooked.com/a/95eb7c92b6fc9f87 – Xeverous Jun 11 '20 at 19:22
  • @Xeverous Added deduction guide `template y_combinator(F)->y_combinator;`, sorry, I think I might have been testing against a non-compliant C++17 compiler. http://coliru.stacked-crooked.com/a/5351d98857d7c39e – Yakk - Adam Nevraumont Jun 11 '20 at 20:44
  • @Yakk-AdamNevraumont Now it works but the lambda can not be used within itself. Any ODR-use of `self` ends in the error `use of '[...]' before deduction of 'auto'`. – Xeverous Jun 12 '20 at 10:42
  • @xeverous set the trailing return type of the lambda explicitly and that error goes away (it is the return type deduction rules) – Yakk - Adam Nevraumont Jun 12 '20 at 12:28
  • This deserves in the standard library. – zwhconst May 28 '21 at 09:18
  • @zwhconst No, we should have access to the this pointer in a lambda. See [p0847](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0847r0.html). – Yakk - Adam Nevraumont May 28 '21 at 14:24
  • 1
    Maybe worth a quick update to say this made it into C++23, albeit with `this` moved to the front of the first function parameter - `(this auto&& self...`; latest revision https://wg21.link/p0847 – Tony Delroy Feb 20 '23 at 23:35
35

It is not directly possible.

However, lambda captures are classes and the address of an object coincides with the address of its first member. Hence, if you capture one object by value as the first capture, the address of the first capture corresponds to the address of the lambda object:

int main() {
    int i = 0;
    auto f = [i]() { printf("%p\n", &i); };
    f();
    printf("%p\n", &f);
}

Outputs:

0x7ffe8b80d820
0x7ffe8b80d820

Alternatively, you can create a decorator design pattern lambda that passes the reference to the lambda capture into its call operator:

template<class F>
auto decorate(F f) {
    return [f](auto&&... args) mutable {
        f(f, std::forward<decltype(args)>(args)...);
    };
}

int main() {
    auto f = decorate([](auto& that) { printf("%p\n", &that); });
    f();
}
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 16
    "the address of an object coincides with the address of its first member" Is it specified somewhere that the captures are ordered, or that there are no invisible members? – n. m. could be an AI Nov 06 '19 at 14:16
  • 36
    @n.'pronouns'm. Nope, this is a non-portable solution. A capture implementation can potentially order the members from largest to smallest to minimize padding, the standard explicitly allows for that. – Maxim Egorushkin Nov 06 '19 at 14:30
  • @n.'pronouns'm. However, functions can return lambdas with `auto` return types and that becomes a platform ABI issue. That probably means that compilers supporting the same ABI have to layout lambda captures in absolutely the same way. – Maxim Egorushkin Nov 06 '19 at 15:20
  • @MaximEgorushkin: Not entirely sure about that. My understanding is that in such cases, the lambda type gets a name for ABI purposes, so you'd also need to standardize that part. There's no point in agreeing on the layout of the members of `__lambda17@foocpp` when compilers don't first agree on the name `__lambda17@foocpp` – MSalters Nov 07 '19 at 13:55
  • @MSalters You are right, name mangling and layout are both ABI issues. And I don't think lambdas are exempt from ABI. – Maxim Egorushkin Nov 07 '19 at 14:01
  • 17
    Re, "this is a non-portable solution." That's another name for _undefined behavior._ – Solomon Slow Nov 07 '19 at 16:50
  • @SolomonSlow I wonder if this actually is *implementation defined* or just blatantly *undefined* behavior? If the latter, then this really really shouldn't be the accepted answer. – ruohola Nov 07 '19 at 17:26
  • 1
    @ruohola Hard to tell. The "address of an object coincides with the address of its first member" is true for *standard-layout* types. If you tested whether the lambda's type was standard-layout without invoking UB, you could then do this without incurring UB. The resulting code would have implementation-dependent behavior. Simply doing the trick without first testing its legality is, however, UB. – Ben Voigt Nov 07 '19 at 17:55
  • 4
    I believe it is *unspecified*, as per § 8.1.5.2, 15: *When the lambda-expression is evaluated, the entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object, and the non-static data members corresponding to the init-captures are initialized as indicated by the corresponding initializer (...). (For array members, the array elements are direct-initialized in increasing subscript order.) These initializations are performed in the (**unspecified**) order in which the non-static data members are declared.* – Erbureth Nov 07 '19 at 18:01
  • A reasonable interpretation of "address of the lambda" is: something that we can call; in other words, that lambda itself. – Kaz Nov 08 '19 at 00:55
  • Capturing the lambda itself by ref (therefore declaring it as std::function as proposed by some solutions below) seems to be a more "portable" option than capturing another param by value. – Abs Nov 13 '19 at 13:24
  • @Abs More "portable" in what way? A reference may get invalidated, capturing by value is the safest. – Maxim Egorushkin Nov 13 '19 at 13:33
  • @MaximEgorushkin sure that capturing by value is safer (but in this particular case, it's usage has an undefined behaviour). This being said, the reference may indeed get invalidated, but without further details of the actual use case, I guess we may reasonably assume he (the dev) is going to manage its references properly (which is out of the question's scope), otherwise that point out a real design issue at the first place using the lambda reference that way. Your second solution or using a functor would be cleaner. – Abs Nov 15 '19 at 22:05
29

One way to solve this, would be to replace the lambda with a hand written functor class. It's also what the lambda essentially is under the hood.

Then you can get the address through this, even without ever assigning the functor to a variable:

#include <iostream>

class Functor
{
public:
    void operator()() {
        std::cout << "Address of this functor is => " << this;
    }
};

int main()
{
    Functor()();
    return 0;
}

Output:

Address of this functor is => 0x7ffd4cd3a4df

This has the advantage that this is 100% portable, and extremely easy to reason about and understand.

ruohola
  • 21,987
  • 6
  • 62
  • 97
  • 10
    The functor can even be declared like a lambda: `struct { void operator()() { std::cout << "Address of this functor is => " << this << '\n'; } } f;` – Erroneous Nov 06 '19 at 19:17
-1

Capture the lambda:

std::function<void ()> fn = [&fn]() {
  std::cout << "My lambda is " << &fn << std::endl;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vincent Fourmond
  • 3,038
  • 1
  • 22
  • 24
  • 1
    The flexibility of a `std::function` is not needed here though, and it comes at considerable cost. Also, copying / moving that object will break it. – Deduplicator Nov 07 '19 at 19:12
  • @Deduplicator why is it not needed, since this is the only anwser that is standard-compliant ? Please give an anwser that works and does not need std::function, then. – Vincent Fourmond Nov 08 '19 at 10:16
  • That seems to be a better and clearer solution, unless the sole point is to get the address of the lambda (which by itself doesn't make much sense). A common use case would be to have access to the the lambla inside itself, for recursion purpose e.g. See: https://stackoverflow.com/questions/2067988/recursive-lambda-functions-in-c11 where the declarative option as function was widely accepted as a solution :) – Abs Nov 13 '19 at 13:12
-7

It is possible but highly depends on the platform and compiler optimization.

On most of the architectures I know, there is register called instruction pointer. The point of this solution is to extract it when we are inside the function.

On amd64 Following code should give you addresses close to the function one.

#include <iostream>

void* foo() {
    void* n;
    asm volatile("lea 0(%%rip), %%rax"
      : "=a" (n));
    return n;
}

auto boo = [](){
    void* n;
    asm volatile("lea 0(%%rip), %%rax"
       : "=a" (n));
    return n;
};

int main() {
    std::cout<<"foo"<<'\n'<<((void*)&foo)<<'\n'<<foo()<<std::endl;  
    std::cout<<"boo"<<'\n'<<((void*)&boo)<<'\n'<<boo()<<std::endl;
}

But for example on gcc https://godbolt.org/z/dQXmHm with -O3 optimization level function might be inlined.

majkrzak
  • 1,332
  • 3
  • 14
  • 30
  • 2
    I'd love to upvote, but I am not very much into asm and don't understand what is happening here. Some explanation of mechanism how it works would be really valuable. Also, what do you mean by "addresses *close to* the function"? Is there any constant/undefined offset? – R2RT Nov 07 '19 at 13:20
  • 2
    @majkrzak This is not the "true" answer, as it is the least portable of all posted. It's also not guaranteed to return the address of the lambda itself. – jonspaceharper Nov 08 '19 at 09:57
  • it states so, but "it is not possible" answer is false asnwer – majkrzak Nov 08 '19 at 09:58
  • The instruction pointer cannot be used to derive addresses of objects with automatic or `thread_local` storage duration. What you are trying to get here is the return address of the function, not an object. But even that won't work because the compiler generated function prologue pushes to the stack and adjusts the stack pointer to make space for local variables. – Maxim Egorushkin Nov 08 '19 at 21:51