D编程语言中的Pimpl习惯用法 D有一个奇妙的模块系统,它比C++更能大大减少编译时间。根据文档,D仍然提供不透明的结构和联合,以便启用pimpl习惯用法。我的问题是:如何在一个模块中声明嵌套结构(或联合)并在另一个模块中定义它?它的语法是什么 C++中的标题看起来像这个< /P> struct S { ... struct Impl; Impl * p; };
实现文件(cpp文件)将使用一些有趣的语法,如:D编程语言中的Pimpl习惯用法 D有一个奇妙的模块系统,它比C++更能大大减少编译时间。根据文档,D仍然提供不透明的结构和联合,以便启用pimpl习惯用法。我的问题是:如何在一个模块中声明嵌套结构(或联合)并在另一个模块中定义它?它的语法是什么 C++中的标题看起来像这个< /P> struct S { ... struct Impl; Impl * p; };,d,pimpl-idiom,D,Pimpl Idiom,实现文件(cpp文件)将使用一些有趣的语法,如: #include "header.h" struct S::Impl { ... }; 如何在D中实现相同的功能?D(至少是DMD)使用.di文件进行声明。它们在某种程度上等同于C.h文件,但它们是可选的。D编译器可以自动生成.di文件(当指定-H开关时),尽管我相信目前它所做的只是剥离函数体和单元测试 下面是使用.di文件实现PImpl的一种方法: mod.di: struct S { struct I; I*
#include "header.h"
struct S::Impl {
...
};
如何在D中实现相同的功能?D(至少是DMD)使用.di
文件进行声明。它们在某种程度上等同于C.h
文件,但它们是可选的。D编译器可以自动生成.di
文件(当指定-H
开关时),尽管我相信目前它所做的只是剥离函数体和单元测试
下面是使用.di
文件实现PImpl的一种方法:
:mod.di
struct S { struct I; I* pi; }
:mod.d
struct S { struct I { int v; } I* pi; }
S
中的字段在.d
和.di
文件中是相同的-如果它们不同,编译模块将对字段的布局有不同的了解,这可能导致内存损坏。当前编译器实现不验证.d
和.di
文件中的定义是否匹配
我的问题是:如何在一个模块中声明嵌套结构(或联合)并在另一个模块中定义它
直截了当地说——这在D中是故意不可能的。这是拥有一个可靠的模块系统的直接结果——每个符号声明都由其内部声明的模块名隐式限定。由于各种原因,您不能将一个符号劫持到另一个模块“名称空间”中
也就是说,使用pimpl方法不需要在同一个模块中执行。您可以参考CyberShadow的答案了解更多详细信息。另一种方法是基于D的类层次系统: 所有对象都显式或隐式继承对象 因此,我们的想法是使用pimpl实现OuterClass,生成相应的 在di文件中,手动从di文件中删除OuterClassPrivate的所有定义 以及pimpl成员的变更声明 例如: 共享库的第一个版本 测试应用: 共享mylib可以通过以下方式构建(在Linux下): 然后编辑生成的di文件: 编译测试itsel 然后我们改变mylib:
编译它并用刚构建的mylib替换第一个版本的二进制共享对象(so文件)。运行测试应用程序不能崩溃,但输出将不同。链接器有责任验证内存布局假设,因为这是唯一知道所有假设的东西,我认为这是不对的。数据结构不会存储到对象文件中。链接器不知道类型。但编译器不(需要)知道
.d
和.di
文件编译.d
文件时,编译器可以验证.d
文件是否对应于.di
文件。我看不出有什么理由在不切实际的情况下无法实现。目前它根本没有做到这一点。
module pimpl.mylib;
class PimplTest
{
this()
{
mImpl = new PimplTestPrivate();
}
~this()
{
}
string sayWhat(string what)
{
return mImpl.ku ~ " " ~ what;
}
private class PimplTestPrivate
{
string ku = "Ku!!1";
}
private PimplTestPrivate mImpl;
}
module main;
import std.stdio;
import pimpl.mylib;
void main()
{
PimplTest t = new PimplTest();
writeln(t.sayWhat("?"));
}
$ dmd -H -c mylib.d -fPIC
$ dmd -ofmylib.so mylib.o -shared -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/phobos/library/is
// D import file generated from 'mylib.d'
module pimpl.mylib;
class PimplTest
{
this();
~this();
string sayWhat(string what);
// NOTE this
private Object mImpl;
}
$ dmd -c main.d /path/to/first/version/of/mylib.di
$ ln -s /path/to/first/version/of/mylib.so .
$ dmd main.o -L-l:mylib.so -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/phobos/library/is:.
$ ./main
Say: ?
module pimpl.mylib;
import std.conv;
class PimplTest
{
this()
{
mImpl = new PimplTestPrivate();
}
~this()
{
}
string sayWhat(string what)
{
return mImpl.getMessage1(mImpl.getValue(), what);
}
private class PimplTestPrivate
{
int getValue()
{
return 42;
}
string ku = "Ku!!1";
string getMessage1(int x, string y)
{
return "x = " ~ to!(string)(x) ~ ", " ~ y;
}
double pi = 22.0/7.0;
}
private PimplTestPrivate mImpl;
}