• ImportCpp编译指示
    • 命名空间
    • 枚举Importcpp
    • 过程Importcpp
    • 封装构造函数
    • 封装析构函数
    • 对象的Importcpp

    ImportCpp编译指示

    注意: c2nim 可以解析C++子集并且知道 importcpp 编译指示模式语言。 没有必要知道这里描述的所有细节。

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

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

    1. # 和C++引擎对接的反例... ;-)
    2.  
    3. {.link: "/usr/lib/libIrrlicht.so".}
    4.  
    5. {.emit: """
    6. using namespace irr;
    7. using namespace core;
    8. using namespace scene;
    9. using namespace video;
    10. using namespace io;
    11. using namespace gui;
    12. """.}
    13.  
    14. const
    15. irr = "<irrlicht/irrlicht.h>"
    16.  
    17. type
    18. IrrlichtDeviceObj {.header: irr,
    19. importcpp: "IrrlichtDevice".} = object
    20. IrrlichtDevice = ptr IrrlichtDeviceObj
    21.  
    22. proc createDevice(): IrrlichtDevice {.
    23. header: irr, importcpp: "createDevice(@)".}
    24. proc run(device: IrrlichtDevice): bool {.
    25. header: irr, importcpp: "#.run(@)".}

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

    命名空间

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

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

    枚举Importcpp

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

    过程Importcpp

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

    • 哈希 # 符号被第一个或下一个参数替换。哈希 #. 后面的一个点表示该调用应使用C++的点或箭头表示法。

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

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

    生成:

    1. x->CppMethod(1, 2, 3)

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

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

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

    1. proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".}
    2. proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".}
    • 上标点 ' 后跟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)

    生成:

    1. x = new Foo(3, 4)

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

    1. proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}
    2.  
    3. let x = newFoo(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;
    • 如果需要更精确的控制, 上标点 ' 可以用在提供的模式里标志泛型类型的具体类型参数。 更多细节,见过程模式中的上标点操作符。
    1. type
    2. VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
    3.  
    4. var x: VectorIterator[cint]

    Produces:

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