Вы можете использовать частичную специализацию шаблона для случая, когда ваша структура данных получена из интерфейса маркера.
Допустим, ваш класс интерфейса маркера выглядит следующим образом:
class ProvidesExternalUseField
{
public:
char GetExtraField () { return 0; }
void SetExtraField (char newVal) {}
};
Это не виртуальнодля цели: мы не хотели бы добавлять указатель vtable в класс данных только для этого.
Теперь давайте реализуем простой контейнерный класс:
template <class T>
class Container
{
public:
char GetExtraValue ()
{
return 0; // here we cannot know if T is derived from the marker
}
private:
T m_t;
};
И вот как мыизмените его, чтобы различать 2 случая:
template <class T, bool DoesTProvideExternalUseField>
class ContainerImpl
{
public:
char GetExtraValue () { return 0; }
private:
T m_t;
};
template <class T>
class ContainerImpl<T, true>
{
public:
char GetExtraValue () { return m_t.GetExtraField(); }
private:
T m_t;
};
template <class T>
class Container: public ContainerImpl<T,
boost::is_base_of<ProvidesExternalUseField,T>::value>
{
};
Теперь вы можете определить структуры следующим образом:
struct A
{
int m_intVal;
};
struct B: public ProvidesExternalUseField
{
char GetExtraField () { return m_extraField; }
void SetExtraField (char newVal) { m_extraField = newVal; }
int m_intVal;
char m_charVal;
char m_extraField;
};
И точно так же использовать класс контейнера:
Container<A> a;
Container<B> b;
Вы также можете дополнительно автоматизировать (шаблонизировать) геттеры и сеттеры в интерфейсе маркера, используя в качестве параметра шаблона указатель на член.