和 类似, importcpp 编译指示一般可以用于引入 C++ 方法或C++符号。 生成的代码会使用C++方法调用的语法: obj->method(arg)

    结合 headeremit 编译指示,这允许与C++库的 草率 接口:

    需要告诉编译器生成C++(命令 cpp )才能使其工作。 当编译器发射C++代码时,会定义条件符号 cpp

    草率接口 示例使用 .emit 来生成 using namespace 声明。 通过 命名空间::标识符 符号来引用导入的名称通常要好得多:

    1. type
    2. IrrlichtDeviceObj {.header: irr,
    3. importcpp: "irr::IrrlichtDevice".} = object

    枚举Importcpp

    importcpp 应用于枚举类型时,数字枚举值用C++枚举类型注释, 像这个示例: ((TheCppEnum)(3)) 。 (事实证明这是实现它的最简单方法。)

    请注意,procs的 importcpp 变体使用了一种有点神秘的模式语言,以获得最大的灵活性:

    • 符号 @ 被剩下的参数替换,用逗号分隔。示例:

    1. proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".}
    2. var x: ptr CppObj
    3. cppMethod(x[], 1, 2, 3)

    生成:

      作为一个特殊的规则来保持与旧版本的 importcpp 编译指示的向后兼容性,如果没有特殊的模式字符(任何一个 #'@ ),那么认为是C++的点或箭头符号,所以上面的例子也可以写成:

      1. proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".}

      请注意,模式语言自然也涵盖了C++的运算符重载功能:

      • 上标点 ' 后跟0..9范围的整数 i 被第i个形参类型替换。 第0位是结果类型。这可以用于将类型传递给C++函数模板。 在 ' 和数字之间可以使用星号来获得该类型的基类型。 (所以它从类型中“拿走了一颗星”; T * 变为 T 。) 可以使用两颗星来获取元素类型的元素类型等。示例:
      1. type Input {.importcpp: "System::Input".} = object
      2. proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
      3.  
      4. let x: ptr Input = getSubsystem[Input]()

      生成:

      1. x = SystemManager::getSubsystem<System::Input>()
      • #@ 是一个支持 cnew 操作的特例。 这是必需的,以便直接内联调用表达式,而无需通过临时位置。 这只是为了规避当前代码生成器的限制。

      例如,C++的 new 运算符可以像这样“导入”:

      1. proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}
      2.  
      3. # 'Foo'构造函数:
      4. proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".}
      5.  
      6. let x = cnew constructFoo(3, 4)

        但是,根据用例, 也可以这样包装:

        封装构造函数

        有时候C++类有一个私有的复制构造函数,因此不能生成像 Class c = Class(1,2); 这样的代码,而是 Class c(1,2); 。 为此,包含C ++构造函数的Nim proc需要使用 构造函数 编译器。 这个编译指示也有助于生成更快的C++代码,因为构造然后不会调用复制构造函数:

        1. # 更好的'Foo'构建函数:
        2. proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}

        封装destruct由于Nim直接生成C++,所以任何析构函数都由C++编译器在作用域出口处隐式调用。 这意味着通常人们可以完全没有封装析构函数! 但是当需要显式调用它时,需要将其封装起来。 模式语言提供了所需的一切:

        1. proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".}

        对象的Importcpp

        泛型 importcpp 的对象映射成C++模板。这意味着您可以轻松导入C++的模板,而无需对象类型的模式语言:

        1. type
        2. StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object
        3. proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.
        4. importcpp: "#[#] = #", header: "<map>".}
        5.  
        6. var x: StdMap[cint, cdouble]
        7. x[6] = 91.4

        生成:

        1. std::map<int, double> x;
        2. x[6] = 91.4;
        • 如果需要更精确的控制, 上标点 ' 可以用在提供的模式里标志泛型类型的具体类型参数。 更多细节,见过程模式中的上标点操作符。

        Produces:

        1. std::vector<int>::iterator x;