Using Objective-C++, can I write a C++ IsObjectiveCClass<T>
template metafunction such that IsObjectiveCClass<T>::value
is true if and only if T is an Objective-C class?
使用Objective-C ++,我可以编写一个C ++ IsObjectiveCClass
Exactly what are ObjC classes from the viewpoint of the C / C++ subset of the language? When used in a C / C++ context, MyClass* pointers seem to behave like ordinary C pointers; does that mean that MyClass is also a C type?
从语言的C / C ++子集的角度来看究竟是什么是ObjC类?当在C / C ++上下文中使用时,MyClass *指针似乎表现得像普通的C指针;这是否意味着MyClass也是C类型?
5 个解决方案
#1
6
Here is a simplistic solution that should work in most (if not all? Can anyone think of when this might fail?) cases (it uses clang 3.0 via xcode 4.2 - use typedefs instead of using aliases for earlier clang versions):
这是一个简单的解决方案,应该适用于大多数(如果不是全部?有人能想到这可能会失败吗?)的情况(它使用clang 3.0通过xcode 4.2 - 使用typedef而不是使用别名用于早期的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) };
};
#2
5
You can read my most recent rant about ObjC++ in this question. Avoid it as much as you can possibly get away with. Definitely don't try to integrate Objective-C into C++ template metaprogramming. The compiler might actually rip a hole in space.
你可以在这个问题上阅读我最近关于ObjC ++的咆哮。避免它尽可能地逃避。绝对不要尝试将Objective-C集成到C ++模板元编程中。编译器实际上可能会破坏空间中的一个洞。
Hyperbole aside, what you're trying to do is likely impossible. Objective-C classes are just structs. (C++ classes actually just structs too.) There's not much compile-time introspection available.
除了夸张之外,你想要做的事情可能是不可能的。 Objective-C类只是结构。 (C ++类实际上也是结构化的。)没有太多的编译时内省可用。
An id
is a C pointer to a struct objc_object
. At runtime, every object is an id
, no matter its class.
id是指向struct objc_object的C指针。在运行时,每个对象都是一个id,无论它是什么类。
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
#3
1
As with the accepted answer, you can test whether the type is convertible to id, in C++17:
与接受的答案一样,您可以在C ++ 17中测试类型是否可以转换为id:
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;
Testing:
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 *>);
I don't know of a way to discover ObjC inheritance relationships at compile-time; in theory they're changeable at runtime so you would have to query the runtime.
我不知道在编译时发现ObjC继承关系的方法;从理论上讲,它们在运行时是可更改的,因此您必须查询运行时。
#4
0
I would create a template specialisation for 'id' and 'NSObject*', but you'll always be working against the language because the ObjC type system is not the C++ type system.
我会为'id'和'NSObject *'创建一个模板特化,但是你总是会对该语言起作用,因为ObjC类型系统不是C ++类型系统。
#5
0
If you look at the implementation of the C++ STL library in Xcode, you can follow the template specialization models of others like std::is_integral
or std::is_floating_point
:
如果你看一下Xcode中C ++ STL库的实现,你可以遵循std :: is_integral或std :: is_floating_point之类的其他模板特化模型:
template <class T> struct isObjcObject : public std::false_type { };
template <> struct isObjcObject<id> : public std::true_type { };
where std::false_type
and std::true_type
are defined in the <type_traits>
header file.
其中std :: false_type和std :: true_type在
If for whatever reason you don't have std::false_type
and std::true_type
(depending on your C++ version), you can define them yourself as such:
如果由于某种原因你没有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> { };
Note that you can also do this for Objective-C classes too:
请注意,您也可以为Objective-C类执行此操作:
template <class T> struct isObjcClass : public std::false_type { };
template <> struct isObjcClass<Class> : public std::true_type { };
#1
6
Here is a simplistic solution that should work in most (if not all? Can anyone think of when this might fail?) cases (it uses clang 3.0 via xcode 4.2 - use typedefs instead of using aliases for earlier clang versions):
这是一个简单的解决方案,应该适用于大多数(如果不是全部?有人能想到这可能会失败吗?)的情况(它使用clang 3.0通过xcode 4.2 - 使用typedef而不是使用别名用于早期的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) };
};
#2
5
You can read my most recent rant about ObjC++ in this question. Avoid it as much as you can possibly get away with. Definitely don't try to integrate Objective-C into C++ template metaprogramming. The compiler might actually rip a hole in space.
你可以在这个问题上阅读我最近关于ObjC ++的咆哮。避免它尽可能地逃避。绝对不要尝试将Objective-C集成到C ++模板元编程中。编译器实际上可能会破坏空间中的一个洞。
Hyperbole aside, what you're trying to do is likely impossible. Objective-C classes are just structs. (C++ classes actually just structs too.) There's not much compile-time introspection available.
除了夸张之外,你想要做的事情可能是不可能的。 Objective-C类只是结构。 (C ++类实际上也是结构化的。)没有太多的编译时内省可用。
An id
is a C pointer to a struct objc_object
. At runtime, every object is an id
, no matter its class.
id是指向struct objc_object的C指针。在运行时,每个对象都是一个id,无论它是什么类。
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
#3
1
As with the accepted answer, you can test whether the type is convertible to id, in C++17:
与接受的答案一样,您可以在C ++ 17中测试类型是否可以转换为id:
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;
Testing:
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 *>);
I don't know of a way to discover ObjC inheritance relationships at compile-time; in theory they're changeable at runtime so you would have to query the runtime.
我不知道在编译时发现ObjC继承关系的方法;从理论上讲,它们在运行时是可更改的,因此您必须查询运行时。
#4
0
I would create a template specialisation for 'id' and 'NSObject*', but you'll always be working against the language because the ObjC type system is not the C++ type system.
我会为'id'和'NSObject *'创建一个模板特化,但是你总是会对该语言起作用,因为ObjC类型系统不是C ++类型系统。
#5
0
If you look at the implementation of the C++ STL library in Xcode, you can follow the template specialization models of others like std::is_integral
or std::is_floating_point
:
如果你看一下Xcode中C ++ STL库的实现,你可以遵循std :: is_integral或std :: is_floating_point之类的其他模板特化模型:
template <class T> struct isObjcObject : public std::false_type { };
template <> struct isObjcObject<id> : public std::true_type { };
where std::false_type
and std::true_type
are defined in the <type_traits>
header file.
其中std :: false_type和std :: true_type在
If for whatever reason you don't have std::false_type
and std::true_type
(depending on your C++ version), you can define them yourself as such:
如果由于某种原因你没有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> { };
Note that you can also do this for Objective-C classes too:
请注意,您也可以为Objective-C类执行此操作:
template <class T> struct isObjcClass : public std::false_type { };
template <> struct isObjcClass<Class> : public std::true_type { };