Эта статья описывает аккуратный прием: http://www.gotw.ca/publications/mxc++-item-4.htm
Вот основная идея. Вам сначала нужен класс IsDerivedFrom (это обеспечивает и время компиляции во время выполнения, проверяя):
template<typename D, typename B>
class IsDerivedFrom
{
class No { };
class Yes { No no[3]; };
static Yes Test( B* ); // not defined
static No Test( ... ); // not defined
static void Constraints(D* p) { B* pb = p; pb = p; }
public:
enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
IsDerivedFrom() { void(*p)(D*) = Constraints; }
};
Тогда Вашему MyClass нужна реализация, это потенциально специализировано:
template<typename T, int>
class MyClassImpl
{
// general case: T is not derived from SomeTag
};
template<typename T>
class MyClassImpl<T, 1>
{
// T is derived from SomeTag
public:
typedef int isSpecialized;
};
и MyClass на самом деле похож:
template<typename T>
class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is>
{
};
Тогда Ваше основное будет прекрасно способ, которым это:
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //ok also
return 0;
}
Ну, статья в ответе выше появившегося в феврале 2002. В то время как это работает, сегодня мы знаем, что существуют лучшие пути. С другой стороны, можно использовать enable_if
:
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
template<typename, typename>
struct is_same {
static bool const value = false;
};
template<typename A>
struct is_same<A, A> {
static bool const value = true;
};
template<typename B, typename D>
struct is_base_of {
static D * create_d();
static char (& chk(B *))[1];
static char (& chk(...))[2];
static bool const value = sizeof chk(create_d()) == 1 &&
!is_same<B volatile const,
void volatile const>::value;
};
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T, typename = void>
struct MyClass { /* T not derived from SomeTag */ };
template<typename T>
struct MyClass<T, typename enable_if<is_base_of<SomeTag, T>::value>::type> {
typedef int isSpecialized;
};
int main() {
MyClass<SomeTag>::isSpecialized test1; /* ok */
MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
}
В Вашем случае единственный способ, которым я вижу, состоял бы в том, чтобы явно специализироваться MyClass
для InheritSomeTag
. Однако работа SeqAn представляет механизм, названный “template sublassing”, который делает то, что Вы хотите †“В, хотя с различным синтаксисом наследования, таким образом, код не совместим с Вашим током main
функция.
// Base class
template <typename TSpec = void>
class SomeTag { };
// Type tag, NOT part of the inheritance chain
template <typename TSpec = void>
struct InheritSomeTag { };
// Derived class, uses type tag
template <typename TSpec>
class SomeTag<InheritSomeTag<TSpec> > : public SomeTag<void> { };
template <class T, class Tag=T>
struct MyClass { };
template <class T, typename TSpec>
struct MyClass<T, SomeTag<TSpec> >
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag<> >::isSpecialized test1; //ok
MyClass<SomeTag<InheritSomeTag<> > >::isSpecialized test2; //ok
}
Это, конечно, выглядит странным и является очень громоздким, но это позволяет истинный механизм наследования с полиморфными функциями, который выполняется во время компиляции. Если Вы хотите видеть это в действии, взглянуть на [приблизительно 115] примеры SeqAn .
Однако я полагаю, что SeqAn является особым случаем, и не много приложений получил бы прибыль от этого чрезвычайно трудного синтаксиса (дешифрующий SeqAn-связанные ошибки компилятора, реальная боль в *ss!)