Automatically determine if a type is an abstract base class through templates at compile time

Is it possible to automatically determine if a class is an abstract base class at compile time?

I have a factory object, which through another common code sometimes gets an instance with the type of an abstract base class. The code does not compile because it calls the new T () on ABC. In the end, I have to specialize the factory object to create code for each ABC, to instead claim (0) in this case. If it were possible to automatically determine if the type is ABC at compile time, this specialization can be automated.

The following is a simplified example:

// this program code compiles w/ gcc 4.4 #include <iostream> #include <typeinfo> // How to automatically specialize this class at compile-time? template<typename T> struct isAbstractBaseClass { enum { VALUE = 0 }; }; // Factory to create T, lives in a struct to allow default template parameters template<typename T, int ABSTRACT = isAbstractBaseClass<T>::VALUE > struct Create { static T* create() { return new T(); } }; // specialize Create for abstract base classes template<typename T> struct Create<T, 1> { static T* create() { std::cout << "Cannot create and Abstract Base Class!\n"; std::cout << "Create failed on type_info::name() = " << typeid(T).name() << "\n"; return 0; } }; struct Foo { Foo() { std::cout << "Foo created\n"; } }; struct Baz { virtual void bar() = 0; // make this an Abstract Base Class }; // template specialize on Baz to mark it as an Abstract Base Class // My Question: is it possible to automatically determine this at compile-time? template<> class isAbstractBaseClass<Baz> { enum { VALUE = 1 }; }; int main() { std::cout << "Attempting to create a Foo class.\n"; delete Create<Foo>::create(); std::cout << "Attempting to create a Baz class.\n"; delete Create<Baz>::create(); return 0; } 

output:

  > c ++ abstract.cpp && ./a.out
 Attempting to create a Foo class.
 Foo created
 Attempting to create a Baz class.
 Cannot create and Abstract Base Class!
 Create failed on type_info :: name () = 3Baz

edit 1 @jwismar pointed me to the Boost is_abstract implementation. Honestly, looking at the code and trying to determine what it does is very painful. Can someone cook what they use? (edit 2 actually, I was looking for the wrong bit of code, and I figured it out below in edit 2)

@raj Yes, there is a limitation that the class must have a standard default constructor. Its not quite general, but it provides functionality for 99% of the types that I care about. Adding the create () method is not an option, because I do not control some of the classes that were wrapped (third-party code).

@DennisZickefoose The code is compiled - using specialized templates for ABC processing. Yes, the design can be improved to ensure that the code that creates the create () method with ABC does not, but this code also performs other duties that make sense for ABC and not for ABC. This will be a serious rewrite at the moment, and I'm looking for a shorter-term solution.

Both @raj and @DennisZickefoose give good tips on the example design and the base code base, but I really only care about the question of how to determine the ABC type of a type at compile time. Preferably without Boost. My justification for such a need is orthogonal to the issue under consideration.

edit 2 Since I cannot answer my question with 100 reputation, I will post my answer here:

I was able to understand the Boost is_abstract code sufficient to create a version of isAbstractBaseClass that works for my needs. It uses SFINAE to return to the check_sig (...) version in the case of type ABC.

 template<class T> struct isAbstractBaseClass { // Inspired by boost/type_traits/is_abstract.hpp // Deduction fails if T is void, function type, // reference type (14.8.2/2)or an abstract class type // according to review status issue #337 template<class U> static char check_sig(U (*)[1]); template<class U> static short check_sig(...); // enum { VALUE = sizeof(isAbstractBaseClass<T>::template check_sig<T>(0)) - 1 }; }; 
+4
source share
2 answers

The Boost Type Traits library has is_abstract functor. You can use this directly or take a look at the implementation and see how they dealt with it.

+4
source

or just delete this:

 // specialize Create for abstract base classes template<typename T> struct Create<T, 1> { static T* create() { std::cout << "Cannot create and Abstract Base Class!\n"; std::cout << "Create failed on type_info::name() = " << typeid(T).name() << "\n"; return 0; } }; 

then the compiler will just throw an error when trying to create abc.

+1
source

All Articles