1

Given that I was passing the undefined function:

void foo(char, short);

I learned how to obtain the type tuple of the arguments by calling decltype(m(foo)) with this function:

template <typename Ret, typename... Args>
tuple<Args...> m(Ret(Args...));

I would now like to pass an undefined method:

struct bar { void foo(char, short); };

I had tried rewriting m like:

template <typename Ret, typename C, typename... Args>
tuple<Args...> m(Ret(C::*)(Args...));

But when I try to call this similarly with decltype(m(bar::foo)) I get the error:

invalid use of non-static member function void bar::foo(char, short int)

How can I pass this method like I did for the function?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    Remember that a non-static member function pointer needs an instance of its class (an object) on which to operate. One way of passing member function pointer(s) with an object is with std::function. See the `print_add` example: http://en.cppreference.com/w/cpp/utility/functional/function – Richard Critten Jul 20 '16 at 13:38
  • @RichardCritten Note the "**undefined** function" and "**undefined** method" `function` objects will not work, they need an address. Frankly I'm not even sure how `decltype(m(foo))` works, I'm just kinda going with it. – Jonathan Mee Jul 20 '16 at 13:41

1 Answers1

2

If you only want to use decltype on it, you simply need an extra &:

decltype(m(&bar::foo))
Holt
  • 36,600
  • 7
  • 92
  • 139
  • Note the "**undefined** method" I can't take the address. I'll bold those in the question so it's clear why this isn't a solution. It's almost like the function was treated as an expression when I passed it. Not sure how to do something similar with a method. – Jonathan Mee Jul 20 '16 at 13:58
  • 1
    @JonathanMee Why do you mean by "**undefined** method"? A method that is declared but not define? If so, the above code work perfectly. The expression you give to `decltype` is never evaluated. – Holt Jul 20 '16 at 13:59
  • "The above code work perfectly"[sic] I'm guessing you didn't test it before you made that statement: http://stackoverflow.com/q/38402133/2642059 It will not work at all. – Jonathan Mee Jul 20 '16 at 14:01
  • 2
    @JonathanMee I did [test it](http://ideone.com/0BlsEt), you did not. There is a **huge** difference between your code and the link you provide: In your code, the `&` is inside the `decltype`. Per the standard *The operand of the decltype specifier is an unevaluated operand* and *An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof*, so **no**, `&bar::foo` will never be evaluated in the above context. – Holt Jul 20 '16 at 14:06
  • Wow... so taking the address doesn't evaluate even though taking the address requires the function to be defined... – Jonathan Mee Jul 20 '16 at 14:11
  • @JonathanMee That's because `decltype` doesn't look at the implementation of functions, only the return types. It knows the expression `&bar::foo` returns a method pointer, it doesn't need to know if it actually works. – KABoissonneault Jul 20 '16 at 14:21
  • 1
    @JonathanMee This is exactly the same behavior as in [this question](http://stackoverflow.com/questions/38373768/shouldnt-decltype-trigger-compilation-of-its-argument) you asked a few days ago - Whatever is inside `decltype()` will **never** be evaluated, so you will never really *"take the address of the function"*. All the compilers needs to know is that `&bar::foo` is of type `void (bar::*) (char, short);`, which it gets from the **declaration**, from this it deduces which overloads of `m` it needs to consider, and from this it can get the return types. – Holt Jul 20 '16 at 14:22