c++ - 在编译时通过模板自动判断类型是否为抽象基类

标签 c++ templates

是否可以在编译时自动判断一个类是否为抽象基类?

我有一个对象工厂,通过其他通用代码,它有时会用抽象基类类型实例化。该代码无法编译,因为它在 ABC 上调用了 new T()。在这种情况下,我最终不得不专门为每个 ABC 创建代码的对象工厂来代替 assert(0) 。如果可以在编译时自动确定类型是否为 ABC,则可以自动进行这种专门化。

一个简化的例子如下:

// 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;
}

输出:

> 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 towards Boost's is_abstract implementation. Honestly, looking at the code and trying to deduce what boost is doing is very painful. Can someone boil down what trick they're using? (edit 2 actually, I was looking at the wrong bit of code, and I figured it down below in edit 2)

@raj Yes, there is a constraint that the class must have a default public constructor. Its not entirely generic, but it provides functionality for 99% of the types I care about. Adding a create() method is not an option because I don't control some of the classes being wrapped (3rd party code).

@DennisZickefoose The code does compile -- with template specializations to handle ABCs. Yes, the design could be improved to ensure the code that instantiates the create() method with an ABC doesn't do so, but that code is also performing other duties which make sense on ABCs and non-ABCs alike. At this point it would be a major re-write and I'm looking for a more short term solution.

Both @raj and @DennisZickefoose make good points about the design of the example and the underlying code base, but I'm really only interested in the topic's question of how to determine ABC-ness of a type at compile time. Preferably without Boost. My rationale for such a need is orthogonal to the question at hand.

edit 2 Since I can't answer my own question with out 100 reputation, I'll post my answer here:

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

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 };
};

最佳答案

Boost Type Traits 库有一个 is_abstract仿函数。您可以直接使用它,也可以查看实现并了解他们是如何处理它的。

关于c++ - 在编译时通过模板自动判断类型是否为抽象基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6157402/

相关文章:

c++ - 返回对数据结构拥有的对象的引用

c++11 - CUDA 8.0 : Compile Error with Template Friend in Namespace

c++ - 为什么这个模板不能编译?

c++ - 如何在不将所有相关代码带到 header 的情况下解决模板成员函数的 undefined reference ?

c++ - 为什么父窗口没有收到来自子组合框的通知?

c++ - GetUserNameExA 函数无法在系统启动时(GINA)提供用户详细信息?

c++ - 通过访问容器的父容器来使用 sigc::mem_fun

c++ - Clang 如何编译模板实例化?

c++ - 是否可以将实现模板特化定义为另一种类型的 typedef?

C++ 菱形接口(interface)继承