Автоматически определять, является ли тип Абстрактным Базовым Классом через шаблоны во время компиляции - PullRequest
4 голосов
/ 28 мая 2011

Можно ли автоматически определить, является ли класс абстрактным базовым классом во время компиляции?

У меня есть фабрика объектов, которая через другой универсальный код иногда создается с использованием типа абстрактного базового класса.Код не компилируется, потому что он вызывает new T () в ABC.Я заканчиваю тем, что вынужден специализировать объектную фабрику для создания кода для каждого 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

edit 1 @jwismar указал мне на реализацию Boost is_abstract.Честно говоря, смотреть на код и пытаться понять, что делает повышение, очень больно.Может кто-нибудь свести на нет какой трюк?( edit 2 на самом деле, я искал не тот бит кода и понял его ниже в edit 2)

@ raj Да, есть ограничение, которое должен иметь классоткрытый конструктор по умолчанию.Он не совсем общий, но он обеспечивает функциональность для 99% типов, которые мне нужны.Добавление метода create () не является опцией, потому что я не управляю некоторыми классами, которые обертываются (сторонний код).

@ DennisZickefoose Код компилируется - со специализацией шаблона для обработки ABC.Да, дизайн мог бы быть улучшен, чтобы гарантировать, что код, который создает экземпляр метода create () с помощью ABC, этого не делает, но этот код также выполняет другие обязанности, которые имеют смысл как для ABC, так и для не ABC.На этом этапе это было бы серьезной перепиской, и я ищу более краткосрочное решение.

И @raj, и @DennisZickefoose делают хорошие замечания по поводу дизайна примера и базовой базы кода,но меня действительно интересует только вопрос о том, как определить ABC-ность типа во время компиляции.Желательно без Boost.Мое обоснование такой необходимости является ортогональным к рассматриваемому вопросу.

edit 2 Поскольку я не могу ответить на свой вопрос без 100 репутации, я выложу свой ответ здесь:

Мне удалось понять код Boost is_abstract, достаточный для создания версии isAbstractBaseClass, которая работает для моих нужд.Он использует SFINAE для возврата к версии check_sig (...) в случае типа 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 };
};

Ответы [ 2 ]

4 голосов
/ 28 мая 2011

Библиотека черт типа Boost имеет функтор is_abstract .Вы можете либо использовать это напрямую, либо взглянуть на реализацию и посмотреть, как они ее обрабатывают.

1 голос
/ 28 мая 2011

или просто удалите это:

// 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...