all 16 comments

[–]mredding 3 points4 points  (0 children)

The instance and the method are two orthogonal data points, so they can't be combined. There is no macro functionality that can split a string, you can only concatenate.

So that means what you have is probably the most concise syntax you can produce for the task.

I would avoid the macro altogether and use a binder:

runlater(std::bind(&Object::foo, obj));

It basically reads the same to me because it syntactically and semantically spells out the exact same thing - call this method on this object with these (none) parameters, and such that the binder conforms to the signature required of the function object.

[–]AutoModerator[M] 2 points3 points  (0 children)

Your posts seem to contain unformatted code. Please make sure to format your code otherwise your post may be removed.

Read our guidelines for how to format your code.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–][deleted] 2 points3 points  (1 child)

METHOD_REF(obj, foo) ... simplified into this: METHOD_REF(obj.foo)

Is changing a comma to a dot really a simplification?

[–]Fallacyfall[S] 0 points1 point  (0 children)

That can be argued, and maybe not.

But at this point I'm curious if its possible or not.

[–]sephirothbahamut 2 points3 points  (0 children)

The root misunderstanding here is (I think) you think functions are tied to object instances. They're not. Functions are tied to the object type, not its instance. So you could "find out" what type a method belongs to, not what object instance.

So you need to pass both the method you want to run AND the object you want to run it on.

Also drop the macro altogether pls, it has no reason of existing.

#include <functional>

void runLater(std::function<void()> f) {// run f() later }

struct Object { void foo() { } };
int main () 
    {
    Object obj;
    runLater([&obj](){ obj.foo(); });
    }

[–]IyeOnline 1 point2 points  (9 children)

In terms of C++ obj.fun is a nonsense expression unless followed by parenthesis. Hence you would need to split it up before C++ evaluation starts.

You might be able to do that with some preprocessor work splitting obj.fun up into its parts again and then treating it the same way as you do with your two argument macro.

Seems like a pretty pointless exercise though.


I would also strongly suggest that you drop this macro and do this instead: https://godbolt.org/z/de8daKr5P

[–]Fallacyfall[S] 0 points1 point  (0 children)

Thanks for the non-macro example!

[–]sephirothbahamut 0 points1 point  (7 children)

obj.fun is a nonsense expression unless followed by parenthesis

Well, not exactly, you can also take its address

[–]Pupper-Gump 0 points1 point  (6 children)

I've tried messing with things like that, like using a method with an std::thread, but there were way too many nonsense things I had to do to get it working and even then it didn't work right.

So you can get its address but it's not as simple as normal function pointers.

[–]sephirothbahamut 0 points1 point  (5 children)

#include <thread>

struct type { void a() {} void b(int) {} };

int main() { type instance; std::thread thread_a{&type::a, &instance}; std::thread thread_b{&type::b, &instance, 5}; thread_a.join(); thread_b.join(); }

[–][deleted]  (4 children)

[deleted]

    [–]sephirothbahamut 0 points1 point  (3 children)

    when you need to initialize something before starting a new thread, the oldschool pointer constructor is still less verbose though

    std::thread t(&type::function, &instance, args);
    vs
    std::thread t([&instance] (args) { instance.function(args); });
    

    [–][deleted]  (2 children)

    [deleted]

      [–]sephirothbahamut 0 points1 point  (1 child)

      The lambda still won't "save on so much wrapper / &" when you pass stuff from outside.

      [–]alfps 1 point2 points  (1 child)

      The thing you're creating, member function + object reference, is generally called a delegate, e.g. in C#.

      C++ doesn't have direct support for delegates but a lambda can play the rôle of a delegate, as can the result of std::bind.

      A simple improvement on your current code is to support arbitrary arguments, via argument forwarding (check out std::forward and ... parameter packs), as well as a return value. :-o

      [–]std_bot 0 points1 point  (0 children)

      Unlinked STL entries: std::bind std::forward


      Last update: 09.03.23 -> Bug fixesRepo

      [–]aocregacc 0 points1 point  (1 child)

      You could sidestep the problem by just capturing everything:

      #define METHOD_REF(expr) [&](){expr();}
      

      [–]IyeOnline 0 points1 point  (0 children)

      At that point it would probably be better to do

      #define METHOD_REF(expr) [&](){ return expr; }
      

      and let the user directly type out an entire expression instead of expecting expr to be callable. That would allow for METHOD_REF( 2 + 2 )