Clang (Apple LLVMコンパイラ)は、Objective-Cのinitやnewを特別扱いしているようです。

次のコードをコンパイルします。

// clang++ -std=c++11 -fobjc-arc -Wall -Wno-unused-variable \
//    -framework Foundation t.mm
extern "C"
{
#import <Foundation/Foundation.h>
}
 
int main()
{
  @autoreleasepool
  {
    auto s1 = [NSMutableString string];
    auto s2 = [NSMutableString new];
    auto s3 = [[NSMutableString alloc] init];
  }
}

すると、

t.mm:10:9: warning: 'auto' deduced as 'id' in declaration of 's1' [-Wauto-var-id]
auto s1 = [NSMutableString string];
^         ~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.

s1がid型に推論されたという警告が出ます。実際、上記stringはNSStringでid型を返すと宣言されています。

// NSString内
+ (id)string;

一方、newやinitもid型を返すと宣言されているのに、s2やs3は警告が出ません。

// NSObject内
- (id)init;
+ (id)new;

試しに、型名を出力させてみます。

extern "C"
{
#import <Foundation/Foundation.h>
}
#import <typeinfo>
#import <cstdlib>
#import <cstdio>
#import <cxxabi.h>
 
template<typename T> void puts_typename(T)
{
  int status;
  auto name = abi::__cxa_demangle(
    typeid(T).name(), nullptr, nullptr, &status);
  if (status == 0)
  {
    puts(name);
    free(name);
  }
}
 
int main()
{
  @autoreleasepool
  {
    auto s1 = [NSMutableString string];
    auto s2 = [NSMutableString new];
    auto s3 = [[NSMutableString alloc] init];
    puts_typename(s1);
    puts_typename(s2);
    puts_typename(s3);
  }
}

結果はこうです。

objc_object*
NSMutableString*
NSMutableString*

やはり、s2とs3はNSMutableStirng*型になっています。

initとnewについては、まるでidではなくinstancetypeと書かれているかのようにコンパイラが特別扱いしているみたいです。

と、ここまで書いてから、この挙動がClang Language Extensions ― Clang 3.4 documentationのRelated result typesに記述されていることに気づきました。initやallocなど特定の名前で始まるメソッドはinstancetype同様の扱いになるということのようでした。

スポンサード リンク

この記事のカテゴリ

  • ⇒ Clangにおけるメソッドの戻り値の型の扱い
  • ⇒ Clangにおけるメソッドの戻り値の型の扱い