I want to make this specialized w/o changing main. Is it possible to specialize something based on its base class? i hope so.
-edit-
I'll have several classes inheriting SomeTag. I dont want to write the same specialization for each of them.
class SomeTag {};
class InheritSomeTag : public SomeTag {};
template <class T, class Tag=T>
struct MyClass
{
};
template <class T>
struct MyClass<T, SomeTag>
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //how do i make this specialized w/o changing main()
return 0;
}
-
In your case, the only way that I see would be to explicitly specialize
MyClass
forInheritSomeTag
. However, the SeqAn paper proposes a mechanism called “template sublassing” that does what you want – albeit with a different inheritance syntax, so the code isn't compatible with your currentmain
function.// 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 }
This certainly looks strange and is very cumbersome but it allows a true inheritance mechanism with polymorphic functions that is executed at compile time. If you want to see this in action, have a look at some SeqAn examples.
That being said, I believe that SeqAn is a special case and not many applications would profit from this extremely difficult syntax (deciphering SeqAn-related compiler errors is a real pain in the *ss!)
-
This article describes a neat trick: http://www.gotw.ca/publications/mxc++-item-4.htm
Here's the basic idea. You first need an IsDerivedFrom class (this provides runtime and compile-time checking):
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; } };
Then your MyClass needs an implementation that's potentially specialized:
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; };
and MyClass actually looks like:
template<typename T> class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is> { };
Then your main will be fine the way it is:
int main() { MyClass<SomeTag>::isSpecialized test1; //ok MyClass<InheritSomeTag>::isSpecialized test2; //ok also return 0; }
-
Well, the article in the answer above appeared in February 2002. While it works, today we know there are better ways. Alternatively, you can use
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 */ }
Konrad Rudolph : Man, I completely forgot about SFINAE when I wrote my answer. Still, I'm letting it stand to show a weird alternative.
0 comments:
Post a Comment