Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adapting a template-provided base class

Tags:

c++

c++11

How would you go about filling-in a method if a base class doesn't provide it. I'd like to reuse the base class method if it is provided.

E.g.:

#include <iostream>
struct Base0 { };
struct Base1 { void m() { std::cout<<"Base1\n"; } };

template<typename T>
struct Derived : public T {
  //if T doesn't provide m, define it here, otherwise reuse the base class method 
  void m(){ /*? std::cout<<"Derived\n"; ?*/ }
};

int main(){
  Derived<Base0> d0;
  d0.m(); //should print "Derived"
  Derived<Base1> d1;
  d1.m(); //should print "Base1"
}
like image 208
PSkocik Avatar asked Feb 18 '16 20:02

PSkocik


2 Answers

With SFINAE, you may do

template<typename T>
struct Derived : public T {
private:
  template <typename U = T>
  auto m_impl(int) -> decltype(std::declval<U&>().m()){ this->U::m(); }

  template <typename U = T>
  void m_impl(... ) { std::cout<<"Derived\n"; }

public:
  void m() { m_impl(0); }
};

Demo

like image 153
Jarod42 Avatar answered Oct 04 '22 18:10

Jarod42


In order to be general, you should define the function anyway under a different signature:

template<typename T>
struct Derived : public T
{
     auto m(std::false_type) { std::cout<<"Derived\n"; }
};

Then you can use the methods given in this thread in order to check whether the base class has the function m():

template <typename...>
using void_t = void;

template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};

template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};

template <typename T>
using has_m = decltype(std::declval<T>().m());

Finally, you can use that as

template<typename T>
struct Derived : public T
{
     auto m(std::true_type) { return T::m(); }
     auto m(std::false_type) { std::cout<<"Derived\n"; }
     auto m() { return m(detect</* const */ T, has_m>{}); }
                                ^^^^^^^^^^
                                //if m() is const
};

DEMO

like image 37
davidhigh Avatar answered Oct 04 '22 18:10

davidhigh