开发者

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> {};
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜