Specializing templates on Objective-C ARC ownership annotations

I'm trying to partially specialize a template on ARC-annotated pointer types, and I'm finding it doesn't work. Specifically, the following fails because the "specialization" for `T __strong*` is never considered, and we always fall back to the specialization for `T*`:

    // clang test.mm -fobjc-arc -ObjC++ -std=c++14

    #import <Foundation/NSObject.h>

    @interface Foo: NSObject
    { }
    @end

    template <typename T> struct Specialize;
    template <typename T> struct Specialize<T*> { static constexpr bool value = false; };
    template <typename T> struct Specialize<T __strong*> { static constexpr bool value = true; };
    static_assert(Specialize<Foo __strong*>::value, "");

    int main() { }

I have a few questions:

- Does this even make sense? I don't know much of Objective-C, so it's possible that treating ownership qualifiers like cv qualifiers is not even sensical.
- If it does make sense, why is it not supported? Is this simply a bug that needs fixing?

Strangely enough, I haven't found anything online regarding this, so I'm turning to this list as a last resort.

Thanks,
Louis

I'm trying to partially specialize a template on ARC-annotated pointer types, and I'm finding it doesn't work. Specifically, the following fails because the "specialization" for `T __strong*` is never considered, and we always fall back to the specialization for `T*`:

   // clang test.mm -fobjc-arc -ObjC++ -std=c++14

   #import <Foundation/NSObject.h>

   @interface Foo: NSObject
   { }
   @end

   template <typename T> struct Specialize;
   template <typename T> struct Specialize<T*> { static constexpr bool value = false; };
   template <typename T> struct Specialize<T __strong*> { static constexpr bool value = true; };
   static_assert(Specialize<Foo __strong*>::value, "");

   int main() { }

I have a few questions:

- Does this even make sense? I don't know much of Objective-C, so it's possible that treating ownership qualifiers like cv qualifiers is not even sensical.
- If it does make sense, why is it not supported? Is this simply a bug that needs fixing?

Somewhat confusingly (for this sort of purpose), the ARC ownership qualifiers magically move to the right place in a declarator when parsed. The qualifier applies to Objective-C object pointer types, and `Foo` is a bare object type, so `Foo __strong *` actually means `Foo * __strong`. This doesn't (and couldn't) happen for an arbitrary template parameter, so `T __strong *` will never match that; it would only match something like `Foo * __strong *`.

John.

CCing Akira, who knows a lot more about this. Interestingly, this works:

template <class T> struct test;
template <class T> struct test<T * __weak> {};
template <class T> struct test<T *> {};

test<Foo * __weak> x; // selects first specialization

But this doesn't:

template <class T> struct test;
template <class T> struct test<T *__strong> {};
template <class T> struct test<T *> {};

test<Foo * __strong> x; // error, specializations are ambiguous

I think the problem here is that T *'s are implicitly __strong when objc-arc is enabled, so the specializations are equivalent. Maybe we could still treat the first specialization as more specialized since it has an explicit __strong. Either way, I think you can work around this by checking if T is an interface type, in which case you know it'll be implicitly __strong.

CCing Akira, who knows a lot more about this. Interestingly, this works:

template <class T> struct test;
template <class T> struct test<T * __weak> {};
template <class T> struct test<T *> {};

test<Foo * __weak> x; // selects first specialization

But this doesn't:

template <class T> struct test;
template <class T> struct test<T *__strong> {};
template <class T> struct test<T *> {};

test<Foo * __strong> x; // error, specializations are ambiguous

I think the problem here is that T *'s are implicitly __strong when objc-arc is enabled, so the specializations are equivalent. Maybe we could still treat the first specialization as more specialized since it has an explicit __strong. Either way, I think you can work around this by checking if T is an interface type, in which case you know it’ll be implicitly __strong.

What I actually want is to check whether `T*` is an arbitrary ARC ownership-qualified pointer. Is there a way to do that? Clearly, the C++ standard library does not have such a type trait :-).

Louis