1

my type aButton has a function pointer so i can define custom actions for each button, i though the easiest way to do this would be to create a lambda and dereference it and pass it to the function pointer of that aButton instance, since i need non-static access to objects outside of the scope of the button class

but i'm stuck trying to figure out how to cast it to the right type and how to call it without getting the errors below... i haven't see many people have luck with this, and using functional doesn't look like i can pass in context???

    // Example program
    #include <iostream>
    #include <string>

    int global1 = 0;
    int global2 = 5;

    class aButton {
    public:
        int status, oldStatus;
        aButton(int initStatus) { oldStatus = status = initStatus; }
        int (aButton::*action)();
    };

    class Thingy {
    private:
        int mode  = 1;
        int value = 0;
    public:
        void reset() { value = 0; }
        void setMode(int newMode) { mode = newMode; }
        void increment() { value = value + global2; }
        //accessors & mutators
    };

    void specialFunction(Thingy *thingyToWorkOn) {
        //do stuff...
    }
    void anotherSpecialFunction(Thingy *firstThingy, Thingy *secondThingy) {
        //more stuff...
    }

    int main() {

        Thingy one;
        Thingy two;

        aButton *on = new aButton(0);
        aButton *speedUp = new aButton(0);

        on->action = &(     //error: taking address of temporary [-fpermissive]
            [&]() {         //error: cannot convert 'main()::<lambda()>*' to 'int (aButton::*)()' in assignment

                //some specific stuff....
                global1 = 1;
                if (global2 < 10) {
                    global2++;
                }
                one.reset();
                two.reset();
                anotherSpecialFunction(&one, &two);
                std::cout << "on action \n";
                return 1;
            }
        );

        speedUp->action = &(    //error: taking address of temporary [-fpermissive]
            [&]() {             //error: cannot convert 'main()::<lambda()>*' to 'int (aButton::*)()' in assignment

                //some specific stuff....
                if (global1) {
                    one.setMode(global2);
                    two.setMode(global2);
                    specialFunction(&one);
                    specialFunction(&two);
                    std::cout << "speedUp action \n";
                    return 1;
                }
                return 0;
            }
        );


        for(int i=0; i<5; i++) {
            //if on pushed
            (on->(on->action))();           //error: expected unqualified-id before '(

            //if speedUp pushed
            (speedUp->(speedUp->action))(); //error: expected unqualified-id before '(
        }

    }
7
  • The type of a lambda is not known at compile time. auto may help you. Or haven't I grasped what you want to do? Commented Aug 15, 2014 at 13:37
  • Looks like you want aButton::action to be type std::function<int()>? Commented Aug 15, 2014 at 13:37
  • Also, be very careful about capturing local variables (one, two) by reference. If the function really is main then I suppose it's ok since main won't return until the program ends, but otherwise it would be asking for trouble. Commented Aug 15, 2014 at 13:41
  • i didn't think i could pass references (pointers in my case on arduino) with std::function<int()> Commented Aug 15, 2014 at 13:43
  • Is there any reason you so enthusiastically allocate objects and use raw pointers? Commented Aug 15, 2014 at 13:45

3 Answers 3

2

I believe that you want aButton::action to be of type std::function<int()> (read: function that takes nothing and returns int) rather than int (aButton::*). This requires the <functional> header. With that change, your assignments could stay the same (minus the leading address-of operator), though as you figured out, you'll need to explicitly state the return type with -> int. The calls would simply take the form (e.g.):

on->action();

One other note: be very careful about capturing local variables (one, two) by reference. If the function really is main then I suppose it's ok since main won't return until the program ends, but otherwise it would be asking for trouble.

Sign up to request clarification or add additional context in comments.

4 Comments

i need access to some variable number of external things, one action might call other objects, and some methods, another action might just call one method that's why i'm leaning towards [&]
@krazyderek Never, ever use [&] on a lambda whose lifetime (or lifetime of copies) outlives the current scope (the next }). There be undefined dragons all about.
@Yakk, i think i'm on the same page, that would be a mind field of garbage references, but the menu lives in a function called from a while loop, alternatively, how would i pass in references to objects i did need if they're changing from one instance of action to another depending on the button instance?
@krazyderek that's going toward another subject, but one option would be to put each captured object in a shared_ptr (since each lambda would be sharing ownership) and capture those shared_ptrs by value. That way it's guaranteed that the captured objects stay alive until all the lambdas are gone.
0

You cannot assign pointer to lambda to pointer to member function. Pointers to member functions may point only to member functions.

You can indeed use std::function from <functional> instead. Declare your action as

std::function<int()> action;

so instead of using member functions you will use global functions. Of course you need to get rid of & operators for lambdas. And you need to modify the way of calling action.

1 Comment

A lambda can capture this, there's no need to have thataButton* there.
0

Thanks guys, i guess functional was what i was looking for after all... this seems to do what i want on http://cpp.sh/8ll i guess i just got confused cause a lot of the functional examples had them as arguments for callbacks instead

    // Example program
    #include <iostream>
    #include <string>
    #include <functional>

    int global1 = 0;
    int global2 = 5;

    class aButton {
    public:
        int status, oldStatus;
        aButton(int initStatus) { oldStatus = status = initStatus; }
        std::function<int()> action;
    };

    class Thingy {
    private:
        int mode  = 1;
        int value = 0;
    public:
        void reset() { value = 0; }
        void setMode(int newMode) { mode = newMode; }
        void increment() { value = value + global2; }
        //...
    };

    void specialFunction(Thingy *thingyToWorkOn) {
        //do stuff...
    }
    void anotherSpecialFunction(Thingy *firstThingy, Thingy *secondThingy) {
        //more stuff...
    }

    int main() {

        Thingy one;
        Thingy two;

        aButton *on = new aButton(0);
        aButton *speedUp = new aButton(0);

        on->action = std::function<int()>(
            [&]() -> int{

                //some specific stuff....
                global1 = 1;
                if (global2 < 10) {
                    global2++;
                }
                one.reset();
                two.reset();
                anotherSpecialFunction(&one, &two);
                std::cout << "on action \n";
                return 1;
            }
        );

        speedUp->action = std::function<int()>(
            [&]() -> int{

                //some specific stuff....
                if (global1) {
                    one.setMode(global2);
                    two.setMode(global2);
                    specialFunction(&one);
                    specialFunction(&two);
                    std::cout << "speedUp action \n";
                    return 1;
                }
                return 0;
            }
        );


        for(int i=0; i<5; i++) {
            //if on pushed
            on->action();

            //if speedUp pushed
            speedUp->action();
        }

    }

3 Comments

Just a drive-by comment: It doesn't hurt to make it explicit, but functions can be implicitly constructed from lambdas, so you don't strictly need the std::function<int()>(...) around them (though I suppose I can't promise that's true with the Arduino compiler).
@dlf functions can be implicitly constructed from ANYTHING if you believe their constructor signatures. ;)
@Yakk I try, but my compiler refuses to respect my beliefs!

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.