3

I have this simple code:

#include <iostream>
#include <functional>

class a {
public:
    a() {
        func = [] {
            static int i = 0;
            i++;
            std::cout << i << std::endl;
        };
    }
    std::function<void()> func;
};

int main()
{
    a a1;
    a1.func();
    a a2;
    a2.func();
}

I expected an output like this:

1
1

But instead it was:

1
2

Then I checked the memory addresses of the lambdas in the two instances of a and they were the same. This means that the lambda is created once and then used in all instances. What I am looking for is to make the constructor create a different lambda every time when it gets called. I turned off the compiler optimizations but there was no effect.

INFO: I am using MSVC.

7
  • 2
    This looks like an XY problem. Why is static int i static, if you do not want shared state ? If you want to store per-instance variables, make them a member of class a, and capture that member in the lambda. Commented Jan 17, 2023 at 11:09
  • @MSalters , the lambda should not capture anything. Commented Jan 17, 2023 at 11:14
  • 5
    "The lambda should not capture anything" - Because? This is an arbitrary restriction, only further supporting the fact this is an XY problem. Commented Jan 17, 2023 at 11:15
  • @IvanVenkov: Non-capturing lambda's can be converted to ordinary function pointers, which are stateless. IOW, a::func can be a void(*)() function pointer, and it will always be the same function pointer. That is the automatic result from your requirement that it doesn't capture. So you really have two incompatible requirements here. Which one is real? Commented Jan 17, 2023 at 11:18
  • 1
    An XY problem is asking about a solution you are fixated upon instead of the actual problem. What you really want is additional data (or this) that is accessible to a WNDPROC. Had you tried asking about that, something like this Q&A would have popped up. Commented Jan 17, 2023 at 11:30

2 Answers 2

6

Conceptually, you do have separate instances of the lambda. What you have witnessed might be a compiler optimization, but the actual issue is that static makes i owned by the function body itself, and thus shared by all instances of your lambda.

What you want instead is to make i a member of each lambda instance, which you can do with an extended capture list:

func = [i = 0]() mutable {
    i++;
    std::cout << i << std::endl;
};
Sign up to request clarification or add additional context in comments.

5 Comments

My purpose is to use a lambda as WNDPROC callback. That's why I believed the lambda shouldn't capture anything. Is there a way to convert a capturing lambda to WNDPROC?
@IvanVenkov capturing lambda can be converted to function pointer only by actually wrapping it into function, so if you want to have different functions then you likely need to wrap the lambda calls into function templates.
Its not possible to create "function" at runtime. And this is what you basically want. If I remember correctly there should be some user data filed which you can use to pass any function object, including lambda, which can be called from single static function.
@IvanVenkov then you should ask a question on what you are actually trying to do, instead of the thing you think a way to go. (the answer is likely a single function keeping per-window data and distinguishing between instances by HWND)
@Revolve_Ocelot exactly.
1

If you are on a C++11 only compiler, you can drop the lambda syntax sugar and return to the function objects (which lambdas are a shorthand version of defining)

struct CallCounter
{
    int i = 0;
    void operator()()
    {
        i++;
        std::cout << i << std::endl;
    }
};

class a {
public:
    std::function<void()> func = CallCounter{};
};

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.