Adapting the base class provided by the template

How would you start filling out a method if the base class does not provide it. I would like to reuse the base class method, if one is provided.

eg:.

#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" } 
+6
source share
3 answers

With SFINAE you can 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

+8
source

To be generic, you must define a 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 to check if the base class has the m() function:

 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 this 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

+2
source

As Aslii Berby said, this is probably not the way we would like. If you want to implement something like hell or political design, the following code might be what you are looking for. In fact, such constructions are used quite often and also have idiomatic value.

 #include <iostream> using namespace std; struct StandardTraits {void foo() {cout << "standard" << endl;}}; struct Traits1 {void foo() {cout << "traits1" << endl;}}; struct Traits2 {void foo() {cout << "traits2"<< endl;}}; template<typename T = StandardTraits> class SomeClass { public: typedef T Traits; void useTraits() {traits.foo();} private: Traits traits; }; int main() { SomeClass<> x; SomeClass<Traits1> y; SomeClass<Traits2> z; x.useTraits(); y.useTraits(); z.useTraits(); return 0; } // output: // standard // traits1 // traits2 

See also: https://en.wikipedia.org/wiki/Policy-based_design

0
source

All Articles