10

I have this code:

struct Foo 
{
    int print(int a, double b);
    int print(int a);
    void print();
    void print(int a, int b, int c);

    void other();
};

I can call

decltype(&Foo::other)

but calling

decltype(&Foo::print)

end with error, which is clear to me.

But how can I specify more "closely" which of the four print methods, I want to resolve to decltype?

I want to further use this in

template <class MT>
struct method_info;

template <class T, class Res, class... Args>
struct method_info<Res(T::*)(Args...)>
{
    typedef std::tuple<Args&&...> args_tuple;
    typedef T ClassType;
    typedef Res RetVal; 
};



template <class MethodType>
void func() {
   typedef method_info<MethodType> MethodInfo;
   .....
}

func<decltype(&Foo::other)>();
....
max66
  • 65,235
  • 10
  • 71
  • 111
Martin Perry
  • 9,232
  • 8
  • 46
  • 114
  • What do you mean by *more "closely"*? If the function is overloaded you have to specify exactly which version you want when using it. – NathanOliver Oct 19 '16 at 15:25
  • Is this the [reference](http://en.cppreference.com/w/cpp/language/overloaded_address) you're looking for? – UKMonkey Oct 19 '16 at 15:27

2 Answers2

6

More "closely", as far as I understand, means you want to specify the function arguments of print. That is, for example, you select int, int, then get back the result-type of Foo{}.print(int{},int{}), and thereafter construct a function pointer from all the available information.

Here is an alias template which does that for you in a general way:

template<typename ... Args>
using ptr_to_print_type = decltype(std::declval<Foo>().print(std::declval<Args>() ...)) (Foo::*)(Args ...);

You could also use std::result_of instead of the std::declval stuff, but I like the latter more.

You can use the above as

func<ptr_to_print_type<int,int> >();

EDIT: as asked for by @JavaLover, which btw seems like an unsuitable name for such horrible C++ shit :-), here is the same as above using std::result_of (untested now tested and wrong):

//------ does not compile for overloaded functions --------
template<typename ... Args>
using ptr_to_print_type = std::result_of_t<decltype(&Foo::print)(Foo, Args ...)> (Foo::*)(Args ...)
//------ does not compile for overloaded functions --------

You could further abstract away the Foo but not the print (unless you're using macros).

davidhigh
  • 14,652
  • 2
  • 44
  • 75
  • This is the best post I found after searching for several hours. Thank. May you also provide the `std::result_of` example, please? – javaLover Feb 16 '17 at 14:09
  • 1
    @javaLover: thanks. I made an edit. – davidhigh Feb 16 '17 at 20:15
  • Thank a lot. In the new `std::result_of` version, the compiler can't resolve the overloaded function, though. Here are [demo](http://coliru.stacked-crooked.com/a/c75739a460787e0e) and [backup](http://ideone.com/3vPkzd). It is confused at `(&Foo::print)`. If I replace the `version2` line with the old `version1` line, it will work. – javaLover Feb 17 '17 at 06:45
  • 1
    @javaLover: mhh, you're right, can't bring it to work either ... seems like a limitation of the second approach (it probably could be done along the lines of [this answer](http://stackoverflow.com/a/17875252/2412846), but it's tedious). This is why I said I like the `decltype / declval` stuff more -- it's rather clear there what is going on. Just read `decltype` as "give me the type" and `declval` as "give me the object (--but without issues caused by a missing default constructor, etc.)". – davidhigh Feb 17 '17 at 15:12
  • This will however fail if the arguments get implicitly converted to the method's proper types: the resulting method pointer will have a different signature than then real one. – Fabio A. Feb 24 '18 at 00:14
3

Not sure about the exact syntax but, in case of method name overloading, you should cast the pointer; something like

static_cast<void(Foo::*)(int, int, int)>(&Foo::print);

In you're interested only in type, should be the template value of the cast

void(Foo::*)(int, int, int)
max66
  • 65,235
  • 10
  • 71
  • 111