Obj-C ++: шаблонная метафункция для распознавания классов Objective-C? - PullRequest
9 голосов
/ 12 августа 2011

Используя Objective-C ++, могу ли я написать метафункцию шаблона C ++ IsObjectiveCClass<T> таким образом, чтобы IsObjectiveCClass<T>::value было истинно тогда и только тогда, когда T является классом Objective-C?

Что такое классы ObjC с точки зрения подмножества языка C / C ++?При использовании в контексте C / C ++ указатели MyClass * ведут себя как обычные указатели C;Означает ли это, что MyClass также является типом C?

Ответы [ 5 ]

6 голосов
/ 16 августа 2011

Вот упрощенное решение, которое должно работать в большинстве (если не во всех? Кто-нибудь может подумать, когда это может произойти сбой?) (В нем используется clang 3.0 через xcode 4.2 - используйте typedefs вместо псевдонимов для более ранних версий clang):

template<class T> struct IsObjectiveCClass 
{ 
  using yesT = char (&)[10];
  using noT = char (&)[1];
  static yesT choose(id);
  static noT choose(...);
  static T make();
  enum { value = sizeof(choose(make())) == sizeof(yesT) }; 

};
5 голосов
/ 12 августа 2011

Вы можете прочитать мою самую последнюю речь о ObjC ++ в этом вопросе . Избегайте этого столько, сколько вы можете сойти с рук. Определенно не пытайтесь интегрировать Objective-C в шаблонное метапрограммирование C ++. Компилятор может фактически вырвать дыру в космосе.

Помимо гиперболы, то, что вы пытаетесь сделать, вероятно, невозможно. Классы Objective-C - это просто структуры. (Классы C ++ на самом деле тоже просто структурируют.) Самоанализ во время компиляции не так доступен.

id - это указатель C на struct objc_object. Во время выполнения каждый объект является id, независимо от его класса.

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;
1 голос
/ 02 декабря 2017

Как и в случае принятого ответа, вы можете проверить, можно ли преобразовать тип в id, в C ++ 17:

template <typename T>
struct is_objc_ptr : std::integral_constant<bool, 
  std::is_convertible_v<T, id> && !std::is_null_pointer_v<T>> {};
template <typename T>
constexpr bool is_objc_ptr_v = is_objc_ptr<T>::value;

Тестирование:

static_assert(!is_objc_ptr_v<nullptr_t>);
static_assert(!is_objc_ptr_v<int>);
static_assert(!is_objc_ptr_v<char *>);
static_assert(is_objc_ptr_v<id>);
static_assert(is_objc_ptr_v<NSObject *>);

Я не знаю способа обнаружить отношения наследования ObjC во время компиляции; в теории они могут изменяться во время выполнения, поэтому вам придется запрашивать время выполнения.

0 голосов
/ 07 сентября 2017

Если вы посмотрите на реализацию библиотеки C ++ STL в XCode, вы можете следовать моделям специализации шаблонов других, таких как std::is_integral или std::is_floating_point:

template <class T> struct isObjcObject     : public std::false_type { };
template <>        struct isObjcObject<id> : public std::true_type { };

, где std::false_type и std::true_type определены в заголовочном файле <type_traits>.

Если по какой-либо причине у вас нет std::false_type и std::true_type (в зависимости от вашей версии C ++), вы можете сами определить их так:

template<bool B>   struct boolean_constant { static constexpr const bool value = B; };

template <class T> struct isObjcObject     : public boolean_constant<false> { };
template <>        struct isObjcObject<id> : public boolean_constant<true> { };

Обратите внимание, что вы можете сделать это и для классов Objective-C:

template <class T> struct isObjcClass        : public std::false_type { };
template <>        struct isObjcClass<Class> : public std::true_type { };
0 голосов
/ 12 августа 2011

Я бы создал специализацию шаблона для 'id' и 'NSObject *', но вы всегда будете работать против языка, потому что система типов ObjC не система типов C ++.

...