2

Suppose you have template method that takes a pointer to a method of any type. Inside that template, is there a way to turn the template argument, which is a method pointer type (void(A::*)() for example), into a function pointer type with the same return type and parameters, but without the class information (void(*)())?

I looked at the <type_traits> header but didn't find anything that would help.

Xeo
  • 123,374
  • 44
  • 277
  • 381
  • @Xeo Thanks! I'd mark it as an answer but you only posted a comment :) –  Dec 09 '12 at 00:39
  • It was incomplete and assumed C++11, but I fleshed it out into an answer now. – Xeo Dec 09 '12 at 01:01

1 Answers1

4

A simple way in C++11 is partial specialization with a variadic template:

template<class PMF> struct pmf_to_pf;

template<class R, class C, class... Args>
struct pmf_to_pf<R (C::*)(Args...)>{
  using type = R(*)(Args...); // I like using aliases
};

Note that you need a seperate partial specialization for const member-functions (and theoretically for ref-qualified ones aswell):

template<class R, class C, class... Args>
struct pmf_to_pf<R (C::*)(Args...) const>{
  using type = R(*)(Args...);
};

With cv-qualifiers ({nil,const}, {nil,volatile}) and ref-qualifiers ({nil, &, &&}), you have a total of 2*2*3 == 12 partial specializations to provide. You normally can leave out the volatile qualification ones, dropping the total down to "just" 6. Since most compilers don't support function-ref-qualifiers, you only need 2 really, but be aware of the rest.


For C++03 (aka compilers without variadic templates), you can use the following non-variadic form:

template<class PMF> struct pmf_to_pf;

template<class Sig, class C>
struct pmf_to_pf<Sig C::*>{
  typedef Sig* type; // 'Sig' is 'R(Args...)' and 'Sig*' is 'R(*)(Args...)'
};

Although this doesn't quite work with cv-qualifiers, since I think C++03 didn't allow cv-qualified signatures (e.g. R(Args...) const) on which you could partially specialize to remove the const.


† The {...} denote a set of a certain qualifier, with nil representing the empty set. Examples:

  • void f() const& would be {const}, {nil}, {&}
  • void f() && would be {nil}, {nil}, {&&}

And so on.

Community
  • 1
  • 1
Xeo
  • 123,374
  • 44
  • 277
  • 381
  • I'd expect `using type = R(*)(C*, Args...);` Am I missing something? Never mind, I reread the OP, it's probably for meta-programming only – sehe Dec 09 '12 at 01:06
  • @sehe: Well, that's how I interpreted the question. If OP wanted the `C*` argument, that's an easy fix after all. – Xeo Dec 09 '12 at 01:30