Reputation: 13451
I have a base class Base
, that a lot of other classes will be derived from. I would like to define:
template<typename Derived>
ostream &operator<< (ostream &o, Derived &derived) {
}
But only for classes derived from Base
. I need all previously defined operator<<
to be used for other types. How to do that? Is that possible?
I cannot create ostream &operator<< (ostream &o, Base &base)
, because I need the exact type to be used in some type traits. Is there any way to "push" the derived type while passing the value as a base type?
Upvotes: 8
Views: 5009
Reputation: 507005
Another option is to derive from a 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 derive them from 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
is already templated it's even more useful (I take it that this is not the case for your code).
Upvotes: 2
Reputation: 361482
You can use is_base_of
class template to ensure that only derived classes of Base
can invoke 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 topic at stackoverflow itself: click here
And here is the definition of static_assert
:
template<bool> struct static_assert;
template<> struct static_assert<true> {};
Upvotes: 1
Reputation: 136276
You can use type traits and SFINAE to let only classes derived from Base into 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'
}
Upvotes: 2
Reputation: 51475
http://www.boost.org/doc/libs/1_46_0/libs/utility/enable_if.html
template<typename Derived>
typename enable_if<is_base_of<Base, Derived>, ostream&>::type
operator<< (ostream &o, Derived &derived)
{
}
Upvotes: 6