C++ 和 Swift:无法使用参数列表“(Int)”调用 'externalMethodName'

C++ and Swift: Cannot invoke 'externalMethodName' with an argument list of '(Int)'


我正在努力构建一个 swift 应用程序,它使用自己编写的 C++ class。 我让它与所需的 Objective-C++ 包装器一起工作,但现在我遇到了问题,我无法使用 int 参数调用外部方法。模糊地它适用于纯数字。

示例如下:

片段来自 Swift class:

let validNumber = 5
let refScen = CppToObjCWrapper()
let result = refScen.getCalcLoad(validNumber!)

CppToObjCWrapper.mm中对应的wrapper方法:

-(float)getCalcLoad:(int)value {
  RefScenLibCpp refScen;
  NSLog(@"Inside Wrapper. Value received: %d", value);
  return refScen.getCalcLoad(value);
}

以及RefScenLibCpp.cpp中的C++方法:

float RefScenLibCpp::getCalcLoad(int value) {
  return result / 255 * 100;
}

如我所说,如果我尝试从 swift class 调用此方法,它会抛出错误:

Cannot invoke 'getCalcLoad' with an argument list of '(Int)'

但是,如果我从 Swift class 调用方法时只使用一个数字,例如:

let result = refScen.getCalcLoad(42)

效果很好!我现在花了很多时间来寻找这个问题,但是当我使用 Objective-C++ 和 C++ 时,我认为我还没有找到正确的答案。使用(非)选项的不同方法没有帮助。更让我感到困惑的是,我有一个类似的 C++ 方法,它接受一个 String 参数,我调用它就像使用 int 参数的方法一样,但这个方法工作得很好。我希望有人能帮助我。

为了演示这个问题,我在 Swift 操场上用一个最小的例子重现了这个错误:

func aFuncTakingInt32(val: Int32) {
    // do stuff
}

let validNumber = 42

aFuncTakingInt32(validNumber)

此代码生成相同的错误:

Cannot invoke 'aFuncTakingInt32' with an argument list of type '(Int)'

如果我们将 validNumber 的类型明确更改为 Int32:

let validNumber: Int32 = 42

或者如果我们在调用函数时从 Int 构造一个 Int32

aFuncTakingInt32(Int32(validNumber))

错误消失,代码 运行 完全没问题。


作为解决此问题的额外有用细节,因为我们尝试使用的方法未在 Swift 中定义,而是在我们导入的 Objective-C++ 文件中定义, 有 IS 一种方法可以准确地找出函数在 Swift 结束时期望的参数类型。如果您键入方法名称,并按住 Alt 键并单击方法名称,您将获得一些有用的信息:

现在我们可以看到 Swift 期望传递给该方法的 显式 类型。在这里,它清楚地标记为 Int32 变量(我们已经知道,因为我们刚刚在 Swift 中编写了该方法)。当我们无法访问源代码或不确定 Swift 如何将代码从一种语言翻译成 Swift.

时,这会非常有用

Swift 的 Int 类型不同于 Objective-C、C、C++ 和许多其他语言的 int 原语。 Swift 的 Int 更类似于 Objective-C 的 NSInteger.

如果我们尝试将 Objective-C 的 NSInteger 传递给此 C++ 方法,它会编译,但可能会生成警告(相对于 Swift 的错误)。那是因为 Objective-C 远没有那么严格并且愿意对基元进行一些隐式转换。

话虽如此,Swift 有一些类型更等同于 C、C++ 和 Objective-C 的 int(以及其他大小的整数)。在这里,我们很可能想要 Int32.

我们可以使用 let result = refScen.getCalcLoad(42) 的原因是因为虽然 42 是一个默认情况下将被解释为 Int 的文字(正如我们在 let validNumber = 42 中看到的), 它也可以解释为许多其他数字类型,包括 Int32 (甚至浮点类型)。

但是,当我们执行以下操作时:

let validNumber = 42

此处,validNumber 必须隐式推断显式类型。它推断的类型是 Int(不同于 Objective-C、C 和 C++ 的 int)。

所以当我们尝试以下操作时:

let validNumber = 42
let result = refScen.getCalcLoad(validNumber)

我们正在尝试将 Int 传递给需要 Int32 的方法,并且因为 Swift 对参数类型非常非常严格,它允许我们通过,它会生成错误(其中 Objective-C 可能会生成警告)。

我们应该能够通过明确声明 validNumber 的类型来解决这个问题,Int32:

let validNumber: Int32 = 42
let result = refScen.getCalcLoad(validNumber)

但另外,如果在 Swift 端将此变量的类型保持为 Int32 没有意义,我们 可以 构造一个Int32Int,所以我们可以这样做:

let validNumber = 42
let result = refScen.getCalcLoad(Int32(validNumber))

作为额外的警告,我们不会 运行 使用 String 解决这个问题,因为 Objective-C 的 NSString 映射到 Swift' s String。我们也不会 运行 解决这个问题 char 映射到 Swift 的 Characterbool 映射到 Swift 的Bool.