Define template function only for classes derived from a single base
I have a base class Base
, that a lot of other classes will be derived from. I would like to define:
template&l开发者_运维技巧t;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?
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)
{
}
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'
}
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).
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> {};
精彩评论