从通用类型创建 NSDecimalNumber 的宏

Macro to create an NSDecimalNumber from generic type

我必须即时创建 NSDecimalNumbers,但问题是有时我正在使用 int, float, double, etc 等类型,而其他类型我正在使用 NSObject*, NSString*, etc

等类型

NSDecimalNumber 的初始化对于这些不同的类型是不同的,而且每一个都打出来是非常耗时的。

我希望制作一个宏来快速排序,这样我就可以传入任何类型,它会自动为我排序。

例如

NSDecimalNumberFrom(5);

NSDecimalNumberFrom(@(5));

NSDecimalNumberFrom(@"5");


#define NSDecimalNumberFrom(__v) ({\
NSDecimalNumber *__nsdn;\
if (strcmp(@encode(__typeof__(__v)),"i")==0 ||\
strcmp(@encode(__typeof__(__v)),"d")==0) {\
__nsdn = [[NSDecimalNumber alloc] initWithDecimal:[@(__v) decimalValue]];\
} else if (strcmp(@encode(__typeof__(__v)),"@")==0) {\
__nsdn = [[NSDecimalNumber alloc] initWithDecimal:[@([__v doubleValue]) decimalValue]];\
} else {\
NSLog(@"Unknown Type");\
raise(SIGSTOP);\
}\
__nsdn;\
})

我创建了以下可以工作的宏,它检查传递值的类型,如果是“i”或“d”(例如 int、float、double 等),它会使用一种初始化方法创建 NSDecimalNumber,但如果 typeof 是“@”(例如 NSString*、NSNumber* 等),它会使用另一种初始化方法创建它。这段代码,如果被编译,将会工作......问题是编译器禁止我使用 运行 它因为它知道其他条件中的代码对于我传入的类型是无效的(即使它永远不会被处决)。

那么我怎样才能说服编译器让我这样做呢?或者有别的办法吗?

我能够通过将传递的任何内容转换为字符串来实现这一点,将错误的类型传递给字符串的格式标识符只会导致警告而不是错误,然后我能够使用 pragma 抑制这些警告(因为无论如何它们永远不会发生,编译器不够聪明,无法知道这一点)。

中提琴,

宏:

    #define NSDecimalNumberFrom(__v) ({\
    _Pragma("clang diagnostic push")\
    _Pragma("clang diagnostic ignored \"-Weverything\"")\
    NSString *__vString = @"0";\
    if (strcmp(@encode(__typeof__(__v)),"i")==0) {\
    __vString = [[NSString alloc] initWithFormat:@"%i", __v];\
    } else if (strcmp(@encode(__typeof__(__v)),"d")==0) {\
    __vString = [[NSString alloc] initWithFormat:@"%f", __v];\
    } else if (strcmp(@encode(__typeof__(__v)),"@")==0) {\
    __vString = [[NSString alloc] initWithFormat:@"%@", __v];\
    } else {\
    NSLog(@"Unknown Type");\
    raise(SIGSTOP);\
    }\
    _Pragma("clang diagnostic pop")\
    [[NSDecimalNumber alloc] initWithString:__vString];\
    })

正在使用:

    NSDecimalNumber *a = NSDecimalNumberFrom(5);
    NSDecimalNumber *b = NSDecimalNumberFrom(@(6));
    NSDecimalNumber *c = NSDecimalNumberFrom(@"7");
    
    NSLog(@"%@", a);//logs 5
    NSLog(@"%@", b);//logs 6
    NSLog(@"%@", c);//logs 7

好的。玩得很开心。与 @Albert Renshaw 版本的不同之处在于,如果输入是无意义的,它将 return NaN

#define ENTYP(__v,__typchar) (strcmp(@encode(__typeof__(__v)),__typchar)==0)
#define STRWF(FORMAT,__s) [NSString stringWithFormat:@FORMAT,__s];
#define NSDecimalNumberFrom(__v) ({\
_Pragma("clang diagnostic push")\
_Pragma("clang diagnostic ignored \"-Weverything\"")\
    NSString *__S = NULL;\
    if (ENTYP(__v,"i")) { __S = STRWF("%i", __v)\
    } else if (ENTYP(__v,"d")) { __S = STRWF("%f", __v)\
    } else if (ENTYP(__v,"@")) { __S = STRWF("%@", __v)\
    } else { __S = @"0"; }\
_Pragma("clang diagnostic pop")\
    [[NSDecimalNumber alloc] initWithString:__S];\
})

-(void)test {
    NSDecimalNumber *i = NSDecimalNumberFrom(2);
    NSDecimalNumber *d = NSDecimalNumberFrom(5.0);
    NSDecimalNumber *s = NSDecimalNumberFrom(@"7");
    NSDecimalNumber *n = NSDecimalNumberFrom(@(13));
    NSDecimalNumber *quatsch = NSDecimalNumberFrom(@"quatsch");

    NSLog(@"i=%@ d=%@ s=%@ n=%@ quatsch=%@",i,d,s,n, quatsch);
    //i=2 d=5.0 s=7 n=13
}