在编译时通过模板自动确定类型是否为Abstract Base Class

时间:2011-05-27 20:32:12

标签: c++ templates

是否可以在编译时自动确定类是否是抽象基类?

我有一个对象工厂,通过其他通用代码,有时会使用Abstract Base Class类型进行实例化。代码无法编译,因为它在ABC上调用新的T()。在这种情况下,我最终必须专门为每个ABC创建代码工厂创建代码而不是断言(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

编辑1 @jwismar向我指出了Boost的is_abstract实现。老实说,查看代码并试图推断出提升正在做的事情是非常痛苦的。有人可以归结为他们使用的技巧吗? (编辑2 实际上,我正在查看错误的代码,我在编辑2中将其计算在下面)

@raj是的,有一个约束,该类必须具有默认的公共构造函数。它不是完全通用的,但它为我关心的99%的类型提供了功能。添加create()方法不是一个选项,因为我不控制一些被包装的类(第三方代码)。

@DennisZickefoose代码确实编译 - 使用模板专门化来处理ABC。是的,可以改进设计以确保实例化具有ABC的create()方法的代码不这样做,但该代码还执行其他对ABCs和非ABC有意义的职责。在这一点上,这将是一个重大的重写,我正在寻找一个更短期的解决方案。

@raj和@DennisZickefoose都对示例的设计和底层代码库有所了解,但我真的只对如何在编译时确定类型的ABC-ness的问题感兴趣。最好没有Boost。我对这种需求的理由与手头的问题是正交的。

编辑2 由于我无法用100个声望回答我自己的问题,我会在这里发布我的答案:

我能够理解Boost is_abstract代码足以创建一个适合我需要的isAbstractBaseClass版本。在ABC类型的情况下,它使用SFINAE回退到check_sig(...)版本。

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

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

或者只是删除它:

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

然后编译器只会在您尝试创建abc时发出错误。