Определение шаблонной функции только для классов, производных от одной базы - PullRequest
8 голосов
/ 24 февраля 2011

У меня есть базовый класс Base, из которого будет получено множество других классов.Я хотел бы определить:

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

Но только для классов, производных от Base.Мне нужно, чтобы все ранее определенные operator<< были использованы для других типов.Как это сделать?Это возможно?

Я не могу создать ostream &operator<< (ostream &o, Base &base), потому что мне нужен точный тип, который будет использоваться в некоторых чертах типа.Есть ли способ «протолкнуть» производный тип при передаче значения в качестве базового типа?

Ответы [ 4 ]

6 голосов
/ 24 февраля 2011

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) 
{

}
2 голосов
/ 24 февраля 2011

Другой вариант заключается в получении из шаблона маркеров

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() { }
};

Затем вывести их из обоих

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

Теперь вы можете записать его в виде

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

Преимуществом этого является его простота. И если Base уже шаблонный это еще более полезным (я понимаю, что это не так, для вашего кода).

2 голосов
/ 24 февраля 2011

Вы можете использовать черты типа и SFINAE для включения в вашу функцию только классов, производных от Base:

#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'
}
1 голос
/ 24 февраля 2011

Вы можете использовать is_base_of шаблон класса, чтобы гарантировать, что только производные классы Base могут вызывать operator<<:

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

Вы можете найти определение is_base_of в другой теме непосредственно в stackoverflow: нажмите здесь

А вот определение static_assert:

template<bool> struct static_assert;

template<> struct static_assert<true> {};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...