0

I want to do the equivalent of the following python code:

class A:   
    def__init__(self):
        self.f = None 
class B:   
    def __init__(self, s, a): # s will be a string a will be an A.
        self.s = s
        a.f = lambda : self._s

a = A() 
b = B('this is b", a) 
print(a.f())

outputs:

this is b

w/o showing all the C++ code, I get an error

error: cannot convert 'C::C(std::__cxx11::string, A)::<lambda()>' to 'std::__cxx11::string (*)() {aka st
d::__cxx11::basic_string<char> (*)()}' in assignment
         a.f = [this]()->std::string {return this->name;};

From an answer to a related question, I see that the type of the lambda function is unique and therefore the assignment fails. Is there a way to make this work?

struct A {
    std::string (*f)(); };

struct B {
    std::string name;

    B(std::string n, A& a)
        : name(n)
    {
        a.f = [this]()->std::string {return this->name;};
    } };

int main() {
    A a;
    B b("this is b", a);
    cout << a.f() << endl; }

Edited version with std::function fails with std::bad_function_call


struct A {
    std::function<std::string ()> f;
};

struct B {
    std::string name;

    B(std::string n, A& a)
        : name(n)
    {
        std::function<std::string ()> f = [this]()->std::string {return this->name;};
        a.f = f;
    }
};

int main()
{
    A a;

    B b("this is b", a);
    std::cout << a.f() << std::endl;
}

Outputs:

this is b

eorojas
  • 73
  • 7
  • @uneven_mark, sorry. this is the first time trying to post a question like this and I thought I had the formating correct, but it changed after posting. I don't see a way to edit the post. Is that possible, or do I need to remove and repost? FYI, I did test the python code before posting, so sans reformating it is correct. Thanks for your feedback. – eorojas Nov 05 '19 at 15:18
  • Under the question and its tags ("c++", "lambda", ...) but above the comments there is a link saying "edit". You can click it and edit your question. I already formatted it so that the code you write between the ``` is shown unchanged, just leave the ``` I put in in-place. – walnut Nov 05 '19 at 15:21
  • @uneven_mark, thanks again. My problem was not understanding the relationship of std::function to lambda expressions. It is a kind of meta-coercion. I've recently been working primarily in python and only started using modern C++ a few months ago. All of the pages that reference lambda expressions should say "see also std::function." – eorojas Nov 05 '19 at 16:06
  • As you correctly observed each lambda has a different type, so lambdas themselves cannot really be saved as members of classes. Lambdas without captures can be converted to function pointers, which can be stored and is what you tried here. But your lambda does capture something, namely `this`. Therefore this doesn't work. `std::function` is a wrapper type that will store the lambda using a method called type-erasure, which you may want to look up. – walnut Nov 05 '19 at 17:23
  • `bad_function_call` means that you didn't assign any function to the `std::function` object. If you look closely, you see that `B(std::string n, A a)` is taking `a` by value. In contrast to Python, arguments are passed by making copies, so here you are assigning the lambda to a *function local copy* of `A a;` from `main`. You want to pass-by-reference, i.e. `B(std::string n, const A& a)`. – walnut Nov 05 '19 at 17:27
  • But again, I have to repeat that translating Python to C++ literally, does not work. Try following a good book, e.g. from the [definite C++ book guide](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). (There are also books for programmers with previous experience.) In contrast to Python, which always gives you nice error messages, C++ is very unforgiving if you do not follow the rules. Most of the time you won't be warned if you break your program. (The exception thrown here for the errorenous `std::function` is already unusually forthcoming behavior.) – walnut Nov 05 '19 at 17:30
  • In my previous comment, I meant `B(std::string n, A& a)`, not `B(std::string n, const A& a)`. And by the way, the reason `std::function` is not mentioned in the context of lambdas is that if you design your program properly according to C++ design patterns, then you won't usually need to store a lambda as data member in this way. `std::function` has a significant performance overhead and some other issues and should be avoided if possible. – walnut Nov 05 '19 at 17:34
  • @uneven_mark, thanks again for all of your comments. Interesting comments about performance. The interfaces I'm creating will hardly ever be called -- only on startup and shutdown. The desire is to avoid sharing a class with a library and instead provide sufficient to lookup an object by name. It may be that the design is non-optimal, but it is in place and we want to limit growing the width of the interface. (I was not here when it was created.) BTW, it has been 10 years since I wrote much C++ so I'm just learning the C++1x+ stuff. Thanks for the link. – eorojas Nov 05 '19 at 21:59

0 Answers0