Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deduce class type from method type in C++ templates?

In templates as shown below, I would like the call Run(&Base::foo) succeed without the need to name the Base type twice (as is done in the compiling Run<Base>(&Base::foo) call). Can I have that? Possibly without adding a ton of Boost headers?

With the provided code, I get an error of:

prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’

(you can fiddle with the snippet at http://ideone.com/8NZkq):

#include <iostream>

class Base {
public:
  bool foo() { return true; }
};

Base* x;

template<typename T>
struct Traits {
  typedef bool (T::*BoolMethodPtr)();
};

template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
  T* y = dynamic_cast<T*>(x);
  std::cout << (y->*check)();
}

int main() {
  Base y;
  x = &y;
  Run<Base>(&Base::foo);
  Run(&Base::foo); // why error?
}
like image 338
akavel Avatar asked Dec 21 '25 14:12

akavel


2 Answers

The T in Traits<T>::BoolMethodPtr is in a non-deduced context, so the compiler will not deduce automatically from the call what type T should be. This is because there could be code like this:

template<typename T>
struct Traits {
  typedef bool (T::*BoolMethodPtr)();
};

template<>
struct Traits<int> {
  typedef bool (Base::*BoolMethodPtr)();
};

Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */

If you can do without the Traits<T> class, you can write Run as:

template<class Class>
void Run(bool (Class::*check)()) {
  Class* y = dynamic_cast<Class*>(x);
  std::cout << (y->*check)();
}

In this context, Class can be deduced to mean Base

like image 76
Bart van Ingen Schenau Avatar answered Dec 24 '25 04:12

Bart van Ingen Schenau


To pick apart a type, any type, use partial specialization. There is no function template partial specialization, so you'll need to directly parameterize the function on its argument type and retrieve the class type inside.

template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this

template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
     typedef C host;
     typedef void sfinae; // disallow function for non ptmf arguments
};

template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
    typedef T BoolMethodPtr; // or something
    typedef typename get_host_class< T >::host host;
}
like image 25
Potatoswatter Avatar answered Dec 24 '25 05:12

Potatoswatter



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!