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

问题描述

|| 是否可以在编译时自动确定某个类是否为抽象基类? 我有一个对象工厂,该对象工厂有时通过其他通用代码被实例化为Abstract Base Class类型。该代码无法编译,因为它在ABC上调用了新的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 尝试创建Foo类。 Foo创建 试图创建一个Baz类。 无法创建和抽象基类! 在type_info :: name()= 3Baz上创建失败 编辑1 @jwismar向我介绍了Boost \的is_abstract实现。老实说,查看代码并试图推断出boost正在做什么是非常痛苦的。有人可以说出他们正在使用的技巧吗? (实际上是编辑2,我在看错误的代码,在下面的编辑2中找到了它) @raj是的,存在一个约束,即该类必须具有默认的公共构造函数。它不是完全通用的,但它为我关心的99%类型提供了功能。添加create()方法不是一种选择,因为我无法控制某些被包装的类(第三方代码)。 @DennisZickefoose代码确实可以编译-带有专门用于处理ABC的模板。是的,可以改进设计以确保使用ABC实例化create()方法的代码不会这样做,但是该代码还可以执行对ABC和非ABC都有意义的其他职责。在这一点上,这将是一个重大的重写,我正在寻找更短期的解决方案。 @raj和@DennisZickefoose都很好地说明了示例的设计和基础代码库,但是我只对主题有关如何在编译时确定ABC类型的问题感兴趣。最好不要使用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 };
};
    

解决方法

        Boost类型特征库具有is_abstract函子。您可以直接使用它,也可以查看实现并查看他们如何处理它。     ,        或只是删除此:
// 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时,编译器只会发出错误。     

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...