0

A very simplified version of my code is this:

#define proxy(name, type, arg) \
    void name(function_list_object* obj, type arg) \
    { \
        void (*foo)(type arg) = obj->find_ptr_for(STRINGIZE(name)); \
        foo(arg); \
    } \

proxy(fi, int, i);

Which works perfectly fine. However with C++11:

proxy(fs, std::string&&, rvrs); 

... expectedly leads to an error, since I need std::move to transfer the rvalue to another level.

I'm thinking of such a solution but I'm not sure it will be always safe:

#if defined(MY_CXX11)
#   define MY_MOVE(x) std::move(x)
#else
#   define MY_MOVE(x) x
#endif

#define proxy(name, type, arg) \
    void name(function_list_object* obj, type arg) \
    { \
        void (*foo)(type arg) = obj->find_ptr_for(STRINGIZE(name)); \
        foo(MY_MOVE(arg)); \
    } \

It seems to me that this will work for all possible types. Am I right?

Borislav Stanimirov
  • 1,609
  • 12
  • 23
  • 6
    Can you elaborate on what is the problem this `proxy` macro solves? As is, I see no point in it (and there is no driving motivation to fix I-don't-know-what: what counts as fixed when you don't have goals?) – R. Martinho Fernandes Jul 02 '13 at 13:45
  • In short, based on arguments that I haven't added to my example, it finds the the pointer to the appropriate actual function to call from a list of function pointers... but I think that's besides the point – Borislav Stanimirov Jul 02 '13 at 13:49
  • 2
    I don't think it's besides the point. If it is, I shall post an answer with "I would just call the function directly" because that's a superior solution. – R. Martinho Fernandes Jul 02 '13 at 13:54
  • 1
    I don't get it. I usually let the compiler do overload resolution. _"it finds the the pointer to the appropriate actual function to call from a list of function pointers"_? – sehe Jul 02 '13 at 13:56
  • usage of macros like this is usually a tell tale of poor coding. (but: boost also uses a lot of macros, though those C++11 headers that are essentially inherited from boost don't) – Walter Jul 02 '13 at 13:57
  • I edited it. It's still oversimplified, but that's the basic idea – Borislav Stanimirov Jul 02 '13 at 14:01
  • looks like a case for perfect forwarding... – Walter Jul 02 '13 at 14:04

1 Answers1

2

You don't need std::move. That turns anything into an rvalue. It will fail if the function takes an lvalue reference, like void foo(int&).

You need std::forward, which forwards arguments exactly as you specify. Just specify that the argument needs to be forwarded as given: std::forward<type>(arg).

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • As a very rough rule of thumb I would say that `std::move` should be more common in client code than in library code, which is likely to make more use of `std::forward`. As I said, very rough, as there are lots of fine exceptions, but I think it's not bad to think with `std::move` as "default" in client code, and `std::forward` as "default" in library code. But please don't take this rule to mean you don't need to understand the differences between the two. – R. Martinho Fernandes Jul 02 '13 at 14:14
  • Thanks. And just out of curiosity, what bad would have happened if I had used std::move? The code `void foo(t&); void proxy(t& a) { foo(move(a)); }` seems perfectly safe (albeit pointless) to me. – Borislav Stanimirov Jul 02 '13 at 14:56
  • It doesn't compile. You cannot bind rvalues to lvalue references (It may compile erroneously on some old versions of Visual Studio) – R. Martinho Fernandes Jul 02 '13 at 14:57
  • Ah! So that was the case with me, then :) – Borislav Stanimirov Jul 02 '13 at 14:58