Define a template function only for classes derived from one database

I have a base class Base , from which many other classes will be derived. I would like to define:

 template<typename Derived> ostream &operator<< (ostream &o, Derived &derived) { } 

But only for classes derived from Base . I need all the previously defined operator<< , which will be used for other types. How to do it? Is it possible?

I cannot create ostream &operator<< (ostream &o, Base &base) because I need the exact type that will be used in some types. Is there a way to “push” a derived type when passing a value as a base type?

+8
c ++ templates
source share
4 answers

http://www.boost.org/doc/libs/1_46_0/libs/utility/enable_if.html

http://www.boost.org/doc/libs/1_42_0/libs/type_traits/doc/html/boost_typetraits/reference/is_base_of.html

 template<typename Derived> typename enable_if<is_base_of<Base, Derived>, ostream&>::type operator<< (ostream &o, Derived &derived) { } 
+6
source share

You can use type traits and SFINAE to allow only classes derived from Base in your function:

 #include <iostream> #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_base_and_derived.hpp> struct Base {}; template<typename Derived> typename boost::enable_if<boost::is_base_and_derived<Base, Derived>, std::ostream&>::type operator<<(std::ostream& o, Derived& derived); struct A : Base {}; struct B : Base {}; struct C {}; int main() { A a; B b; C c; std::cout << a << '\n'; // compiles std::cout << b << '\n'; // compiles std::cout << c << '\n'; // error: no match for 'operator<<' in 'std::cout << c' } 
+2
source share

Another option is to output from the marker template

 struct Base { /* ... */ }; template<typename T> struct BaseOutputtable { T *getDerived() { return static_cast<T*>(this); } T const *getDerived() const { return static_cast<T const*>(this); } protected: ~BaseOutputtable() { } }; 

Then print them out of both

 struct MyDerived : Base, BaseOutputtable<MyDerived> { /* ... */ }; 

Now you can write it as

 template<typename Derived> ostream &operator<< (ostream &o, BaseOutputtable<Derived> &derived) { /* ... */ } 

The advantage of this is its simplicity. And if Base already templated, it is even more useful (I believe this is not the case for your code).

+2
source share

You can use the is_base_of class template to ensure that only derived Base classes can call operator<< :

 template<typename Derived> ostream &operator<< (ostream &o, Derived &derived) { static_assert<is_base_of<Base, Derived>::value>(); } 

You can find the definition of is_base_of in another section on the stack itself: click here

And here is the definition of static_assert :

 template<bool> struct static_assert; template<> struct static_assert<true> {}; 
+1
source share

All Articles