接入SDK时移植代码发现报错了。
Too many arguments provided to function-like macro invocation
Parentheses are required around macro argument containing braced initializer list
代码如下:
IEagle_setRespCallback(^(BOOL isSuccess, id object) {
if (isSuccess) {
NSLog(@"Demo:%@", @"二次验证(登录验证)回调成功");
/** 收到二次验证回调成功后 方可进入游戏 */
testCount = testCount + 1;
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"1", @"2", nil];
} else {
NSLog(@"Demo:%@",@"二次验证(登录验证)回调失败");
}
});
这个NSDictionary 初始化的代码应该没什么问题的,但是在Block里面缺报错了。奇怪了。
方法一:事实上Xcode自带提示了Fix功能,点击Fix后问题解决了
IEagle_setRespCallback((^(BOOL isSuccess, id object) {
if (isSuccess) {
NSLog(@"Demo:%@", @"二次验证(登录验证)回调成功");
/** 收到二次验证回调成功后 方可进入游戏 */
testCount = testCount + 1;
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"1", @"2", nil];
} else {
NSLog(@"Demo:%@",@"二次验证(登录验证)回调失败");
}
}));其实Xcode给出的解决办法就是在匿名Block之间加了对括号。
报错的翻译为:
为类似宏调用的函数提供的参数太多
包含大括号初始值设定项列表的宏参数周围需要括号
方法二: 就是不要用匿名Block
void(^loginCallback)(BOOL, id) = ^(BOOL isSuccess, id object) {
if (isSuccess)
{
NSLog(@"Demo:登录成功");
NSDictionary *dic1 =[NSDictionary dictionaryWithObjectsAndKeys:gameId,@"sdk_gameId",
channelId,@"sdk_channelId" ,
appId,@"sdk_appId" ,
sessionId,@"sdk_sid" ,
extra, @"sdk_extra",
nil];
[stifle_gas sendU3dMessage:@"LoginSdkCallBack" param:dic1 resultString:nil];
}
else
{
NSLog(@"Demo:登录失败[%@]", (NSString *)object);
}
};
// 登录回调
IEagle_setLoginCallback(loginCallback);
方法三:在编译有问题的地方直接加括号,当然这样写代码不太方便
// 二次验证回调
IEagle_setRespCallback(^(BOOL isSuccess) {
if (isSuccess) {
NSLog(@"Demo:%@", @"二次验证(登录验证)回调成功");
/** 收到二次验证回调成功后 方可进入游戏 */
([NSString stringWithFormat:@"%@", @"test"]);//这里加一对括号就能编译通过了
} else {
NSLog(@"Demo:%@",@"二次验证(登录验证)回调失败");
}
});
原理分析
找了很久都只有一篇有用的文章http://www.it1352.com/470834.html
int val1 = 0; int val2 = 1; const auto check = [val1,val2]()-> bool { return val1 < val2; }; // no error for this call assert(check() && "Test is failed"); // no error for this call assert([=]()-> bool { return val1 < val2; }() && "Test is failed");
//compile error for this call "too many arguments provided to function-like macro invocation" assert([val1,val2]()-> bool { return val1 < val2; }() && "Test is failed");
The problem is the comma in the capture list.
The preprocessor has an extremely limited understanding of the C++ syntax, it mainly does trivial text substitution. If a comma is not between matching inner parenthesis (and not part of a token like a string literal of course), the preprocessor will treat it as a separator of arguments of the macro invocation.
So the preprocessor thinks you are invoking assert with the two arguments [this and the rest of the stuff behind the first comma, which yields the error.
You can fix this error by using an extra set of parenthesis:
The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments. If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives,155 the behavior is undefined.
翻译后的关键文字如下:
编译错误当我使用assert宏并在捕获列表中使用多个参数定义lambda(匿名函数)时会出现这种情况?
问题是逗号在捕获列表中。
预处理器对C ++语法的理解非常有限,它主要是简单的文本替换。如果逗号不在匹配的内括号之间(而不是像字符串文字一样的令牌的一部分),预处理器将它作为宏调用的参数的分隔符。
因此,预处理器认为你使用两个参数 [this ]和第一个逗号后面的其他东西调用assert,产生错误。
您可以使用一组额外的括号来修复此错误:
int i = -7,j = 7; assert(([i,j](){return i + j;}()));
总结:
宏定义函数IEagle_setRespCallback调用了捕获列表中使用多个参数定义lambda(匿名函数)^(BOOL isSuccess, id object) { , ,}时,预处理器对C ++语法的理解非常有限,它主要是简单的文本替换。如果逗号不在匹配的内括号之间(而不是像字符串文字一样的令牌的一部分),预处理器将它作为宏调用的参数的分隔符。
宏定义函数 + lambda(匿名函数)逗号,这时要多加一对括号来区分匿名函数的参数和宏定义的参数。