从定义中分割声明

时间:2013-08-05 21:35:23

标签: d

我真的想使用D,因为它的语言结构所以很多我关心的东西比C ++更好,但几乎强制的GC(issue handled [sort of] here),稍微不那么强大的运算符重载(opDispatch除外。opDispatch性感),以下问题有点让我失望。

D中是否可以从定义中拆分方法声明?如果是这样,怎么样?如果没有,为什么?

'how'的激励示例:为了将实现隐藏在用户代码编写者的眼睛之外,提供二进制对象旁边的接口函数的小头文件,如C头和库一样。偏好:不取决于用户代码是否已经黑客攻击垃圾收集器,或者只是在没有druntime的情况下编译(such as this中找到here)。

3 个答案:

答案 0 :(得分:4)

如果我像这样编写一个D文件:http://arsdnet.net/dcode/iface/test.d并使用dmd -c编译,你会看到它没有错误;这是一个有效的D文件。该语言允许您编写函数原型而无需实现。

.di文件就是这样,它只是有一个不同的文件名。

然后给出main:http://arsdnet.net/dcode/main.d如果你编译dmd main,当它看到“import iface.test;”时,会自动搜索iface / test.d,找到.d文件,或者.di if你重命名它但是同样的东西,并获得你的接口定义。

dmd main将因链接器错误而失败,因此我们需要实现它:http://arsdnet.net/dcode/impl.d注意:impl不会导入模块,因此它永远不会检查其他文件。保持.di和.d文件同步是一个棘手的部分,除非你自动生成接口文件,因为未定义的方法会给链接器错误,但方法的顺序很重要:它必须匹配,所以变量列表,如果有任何公共变量。否则,使用代码和实现代码将不同意类的布局。

同样,它自动检查,实现文件根本不查看“header”文件,所以这与C ++的一个主要区别是你编写头文件一次,然后在使用程序和实现文件中使用它。

您会注意到实现文件也列出了类等。 D不支持void MyClass::add(int a) {}语法C ++必须在类外编写方法。

据我所知,没有办法强制实现文件查找头文件,如果你把两个都放在命令行上,你会得到:“错误:来自文件iface / test.d的模块iface.test冲突使用文件impl.d中的另一个模块测试“

建议使用.di文件的方法是使用dmd -H自动生成它们。这将读取完整的实现文件并删除函数体,只留下定义。当他们说这是编译器的一个特性时,这部分可能是关键的一点 - .di文件是有效的标准D,但是通过编译器选项生成,不一定需要成为其他编译器的一部分。

答案 1 :(得分:3)

您可以使用extern声明函数而不指定其实现,例如:

extern(D):
void foo(string name);

然后简单地提供一个目标文件/存档以及用于链接的实现。请注意,模块名称是函数的错误名称的一部分,因此头文件需要与编译模块相同的模块名称,或者您可以使用extern(C)禁用修改(排除重载并使用C调用约定)。 / p>

答案 2 :(得分:3)

亚当已经解释了一切。我将尝试添加一个额外的例子:

假设您正在开发一个名为 mylib 的库,它具有函数foo()和bar()。您的代码和库测试应用程序在开始时可能如下所示:

mylib.d - 界面文件

module mylib;

void foo();
void bar();

mylib_impl.d - 定义在这里

module mylib;

import std.stdio;

void foo() {
  writeln("foo()");
}

void bar() {
  writeln("bar()");
}

mylib_test.d - 测试应用

// To compile: dmd mylib_impl.d mylib_test.d
// NOTE: we do not compile the "interface" file mylib.d !!
module mylib_test;

import mylib;

int main() {
  foo();
  bar();

  return 0;
}

现在应该不难理解我们的.di文件纯粹是为了方便和清晰。如果我们决定使用接口文件,我们会将mylib.d重命名为mylib.di,将mylib_impl.d重命名为mylib.d。 mylib_test.d将保持不变。