Подтвердить что ты не робот

Могут ли новые литералы Clang Objective-C перенаправляться на пользовательские классы?

Хотя перегрузка @ начинает наступать на опасную территорию, мне нравится добавлять новые литералы Objective-C в Clang 3.1. К сожалению, новые литералы для меня ограничены. За исключением случаев, когда код должен взаимодействовать с AppKit, я в основном отказался от использования классов Foundation в пользу собственной собственной инфраструктуры (по разным причинам, большинство из которых заключается в том, что мне нужен прямой контроль над используемыми шаблонами распределения памяти по объектам).

Я всегда мог использовать некоторую хитрость времени выполнения, чтобы передать вновь созданный объект в качестве моего собственного класса (и это то, что я уже должен делать с литералами строковых объектов, поскольку только среда выполнения без использования Apple поддерживает флаг -fconstantstring=class)., но это взлом в лучшем случае и выбрасывает все преимущества, которые я получил, заменив эквивалентный класс Foundation для начала.

В отличие от литералов строковых объектов, новые литературные инструменты Clang не являются фактически постоянными классами (где макет памяти жестко запрограммирован); вместо этого соответствующие сообщения отправляются в соответствующие классы для создания и инициализации нового объекта во время выполнения. Эффект ничем не отличается, если вы сами создали объект. Теоретически это означает, что используемые классы и методы, называемые новыми литералами, не являются жестко закодированными. На практике я не могу найти способ изменить их, чтобы указать на мои собственные пользовательские классы и методы (на самом деле я был бы счастлив просто указать на собственный класс, указывая на фиктивный метод на фактический метод во время выполнения, не сложно).

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

4b9b3361

Ответ 1

Вы можете заменить класс для некоторых Objective-C литералов трюком @compatibility_alias.

Вот пример.

@compatibility_alias NSNumber AAA;

Конечно, вы должны обеспечить правильную реализацию для нового класса.

#import <Foundation/NSObject.h>

@interface  AAA : NSObject
+ (id)numberWithInt:(int)num;
@end

@implementation AAA
+ (id)numberWithInt:(int)num
{
    return  @"AAAAA!!!";    // Abused type system just to check result.
}
@end

@compatibility_alias NSNumber AAA;

Теперь Кланг выполнит эту работу за вас. Я подтвердил, что это работает для чисел, массивов, словарных литералов. К сожалению, строковые литералы, кажется, испускаются статически, поэтому это не сработает.

Подробнее о @compatibility_alias ключевом слове см. здесь.

Примечание

Поскольку ключевое слово @compatibility_alias - это директива компилятора, которая применяется к текущему модулю компиляции, вам нужно отделить блок компиляции, чтобы избежать дублирования символов с классом NSObject в Apple Foundation Kit. Вот как я это сделал.

main.m

#import "test.h" // Comes before Foundation Kit.
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        NSLog(@"return of test = %@", test());
        // insert code here...
        NSLog(@"Hello, World!");

    }
    return 0;
}

test.h

id test();

test.m

#import "test.h"
#import <Foundation/NSObject.h>

@interface  
AAA : NSObject
+ (id)numberWithInt:(int)v;
+ (id)arrayWithObjects:(id*)pobj count:(int)c;
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c;
@end
@implementation AAA
+ (id)numberWithInt:(int)v
{
    return  @"AAAAA as number!!!";
}
+ (id)arrayWithObjects:(id*)pobj count:(int)c
{
    return  @"AAAAA as array!!!";
}
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c
{
    return  @"AAAAA as dictionary!!!";
}
@end



@compatibility_alias NSDictionary AAA;
@compatibility_alias NSArray AAA;
@compatibility_alias NSNumber AAA;



id test()
{
//  return  @{};
//  return  @[];
    return  @55;
}

Результат.

2013-03-23 08:54:42.793 return of test = AAAAA!!!
2013-03-23 08:54:42.796 Hello, World!

Ответ 2

В комментариях есть все правильно, но просто для подведения итогов:

  • Нет.

Значения букв Apple @{}, @[] и @"" жестко закодированы в Clang. Вы можете увидеть это здесь: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?view=markup Все это довольно модульно, что означает, что хакеру Clang не составит труда добавить свой собственный литерал синтаксис... но "модульный" не означает "доступный извне". Добавление нового синтаксиса или даже перенаправление существующего синтаксиса на новые классы, безусловно, потребует восстановления Clang самостоятельно.

Вот сообщение в блоге о добавлении NSURL литералов к Clang, взломав его внутренности: http://www.stuartcarnie.com/2012/06/llvm-clang-hacking-part-3.html (спасибо @Josh Caswell)


Если вы хотите использовать Objective-C ++ с расширениями С++ 11, вы можете иметь "пользовательские литералы", которые позволяют писать такие вещи, как

NSURL *operator ""URL (const char *s) { return [NSURL URLWithString: @(s)]; }

int main() {
    ...
    NSURL *myurl = "ftp://foo"URL;
    ...
}

Это было упомянуто в комментариях к блогу Майка Эша. http://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.html Но это выглядит не очень хорошо Objective-C -ish (или очень С++ ish!), и работает только с Objective-C ++ 11 компилятор, и вообще, пожалуйста, не делайте этого.:)