Type traits to identify pointers to ObjC types?

Hello.

Does clang support any built-in type trait to identify if a given T* is
a pointer to an ObjC class?

This could be useful to specialize some templates in library code
that is meant to be useful in ObjectiveC++ mode.

For example, some non-STL generic containers like Qt ones (especially QList),
use a trick to reduce code size: they use a non-template internal implementation
that handles void* elements, and then cast to the specific types in a lightweight
templated wrapper. For this reason, i believe ARC breaks with Qt containers,
while it works like a charm with the STL.
Should they want to make Qt containers work with ARC, they'd need to know
when they're dealing with ObjC objects pointers and someway specialize the
implementation.

Does such a trait exist? If not (as I suppose), what do you think about adding it?

Thanks,
Nicola

Is this actually required to accomplish what you want? Any Objective-C type can be implicitly cast to id, so if you have a template specialisation that uses id then it will be selected for any Objective-C type. You can, for example, implement something like this:

template<typename T>
bool is_objc_type(T x) { return false; }

template<>
bool is_objc_type(id x) { return true; }

Which will return true when called with an Objective-C type as an argument and false when called with any other type.

The reason ARC will break with the Qt containers (as you have explained them, and without looking at the code) is that casting Objective-C types to void* is not allowed even with an explicit cast. It requires a bridged cast to ensure that ownership is preserved.

This works with the STL templates because Objective-C types in ARC mode are implicitly non-POD types and have custom behaviour for assignment and so the compiler will instantiate the templates and insert the objc_retain() and friends calls as required.

David

Is this actually required to accomplish what you want? Any Objective-C type can be implicitly cast to id, so if you have a template specialisation that uses id then it will be selected for any Objective-C type. You can, for example, implement something like this:

template<typename T>
bool is_objc_type(T x) { return false; }

template<>
bool is_objc_type(id x) { return true; }

Which will return true when called with an Objective-C type as an argument and false when called with any other type.

Well, that doesn't seam to work, because overloading resolution
rules seems to always prefer the template version.

I had to write something like:

template<typename T>
inline typename std::enable_if<!std::is_convertible<T, id>::value, bool>::type
is_objc_type(T t) { return false; }

inline bool is_objc_type(id obj) { return true; }

But you got the point, yes, an intrinsic is not needed.
However, this is still possible only in C++11 mode with
the is_convertible type trait, or am I missing something?

The reason ARC will break with the Qt containers (as you have explained them, and without looking at the code) is that casting Objective-C types to void* is not allowed even with an explicit cast. It requires a bridged cast to ensure that ownership is preserved.

This works with the STL templates because Objective-C types in ARC mode are implicitly non-POD types and have custom behaviour for assignment and so the compiler will instantiate the templates and insert the objc_retain() and friends calls as required.

I know. That's why an hypotetical ARC-friendly Qt implementation (or any similar piece of code)
would need to specialize properly on ObjC types, to avoid those void* tricks.

David

Thanks,
Nicola

This kind of thing works fine in C++98/03 as well. It’s probably worth checking that T is a pointer type, so you don’t treat something like

struct X {
operator id() const;
};

as an Objective-C pointer type.

  • Doug

This kind of thing works fine in C++98/03 as well. It's probably worth checking that T is a pointer type, so you don't treat something like

struct X {
  operator id() const;
};

as an Objective-C pointer type.

Thanks.
What about the standard is_base_of trait? libc++ implements
it with an intrinsic, if supported, or with template tricks if not.
Looking at it, the "tricks" version should already work with Objective-C types
(apart from a is_class check, maybe) while the clang intrinsic seems not.
Could it be possible to make it work with Objective-C types?

Same thing with other traits, like is_class. Should they return
sensible answers on Objective-C types?

  - Doug

Nicola

This kind of thing works fine in C++98/03 as well. It's probably worth checking that T is a pointer type, so you don't treat something like

struct X {
  operator id() const;
};

as an Objective-C pointer type.

Thanks.
What about the standard is_base_of trait? libc++ implements
it with an intrinsic, if supported, or with template tricks if not.
Looking at it, the "tricks" version should already work with Objective-C types
(apart from a is_class check, maybe) while the clang intrinsic seems not.
Could it be possible to make it work with Objective-C types?

Yes.

Same thing with other traits, like is_class. Should they return
sensible answers on Objective-C types?

Yes, they should return sensible answers for Objective-C types.

  - Doug