d与C++互操作
为什么是D
?
强类型
系统编程语言
原型
立即投入生产
最佳C++
集成,出色的C集成
支持的特征
几乎
所有东西
class/struct,ref,指针,const,nothrow...
模板(!)
重载
运算符(!!)
异常(!!!)
第0步,组织
+agora
|-dub.json
|-source/agora
|-source/scpd
|-source/scpp
第一步:构建系统
"preGenerateCommands": [
"$DUB --verbose --single scripts/build_scpp.d"
],
"sourceFiles-posix": [
"source/scpp/build/*.o"
],
"sourceFiles-windows": [
"source/scpp/build/*.obj"
],
"versions": [ "_GLIBCXX_USE_CXX98_ABI" ],
"dflags": [ "-extern-std=c++17" ],
"lflags-posix": [ "-lstdc++" ],
第 2 步:了解目标
//目标:
CppRuntime_Clang => OSX, Linux, Windows
CppRuntime_Gcc => Linux (OSX in the future?)
CppRuntime_Microsoft => Windows
第3步:简单的东西
extern(C++) struct Foo { int a; }
extern(C++) void func1 (ref const(Foo) f);
extern(C++) void func2 (const(Foo*) f);
extern(C++) void func3 (const(Foo**) f);
//
struct Foo { int a; };
void func1 (Foo const& f);
void func2 (Foo const* f);
// void func2 (Foo const* const f);
void func3 (Foo const* const* f);
D代码:遵循D规则
名字空间:
extern(C++, "dlang", "awesome", "app") void awesomeFunc ();
// 不要这样:
extern(C++, dlang.awesome.app) void lessAwesome ();
static assert( lessAwesome.mangleof ==
dlang.awesome.app.lessAwesome.mangleof);
更灵活
的名字空间:
version (CppRuntime_Clang)
enum StdNamespace = AliasSeq!("std", "__1");
else
enum StdNamespace = "std";
// 注意括号
public extern(C++, (StdNamespace)) struct equal_to (T = void) {}
简单方便:
public extern(C++, (StdNamespace)) struct pair (T1, T2)
{
T1 first;
T2 second;
}
注意:混杂|虚表/偏移|大小|生命期函数(ctor/dtor/copy/move)
.
混杂
用pragma(mangle, str)
.虚表/偏移|大小
通过测试
,生命期
用ref/指针/包装器
.
测试大小
static foreach (Type; GlueTypes)
extern(C++) ulong cppSizeOf (ref Type);
/// 检查大小
unittest
{
foreach (Type; GlueTypes)
{
Type object = Type.init;
assert(Type.sizeof == cppSizeOf(object),
format("'%s'的类型大小不匹配: %s (D) != %s (C++)",Type.stringof, Type.sizeof, cppSizeOf(object)));
}
}
测试布局
/// 构内包含字段的`大小/偏移`.
extern(C++) struct FieldInfo { long size, offset; }
static foreach (Type; GlueTypes)
extern(C++) FieldInfo cppFieldInfo (ref Type, const(char)*);
再来:
/// 检查C++构/对象的大小和布局
unittest
{
foreach (Type; TypesWithLayout)
foreach (idx, field; Type.init.tupleof) {
auto object = Type.init;
auto field_info = cppFieldInfo(object,
Type.tupleof[idx].stringof.toStringz);
assert(typeof(field).sizeof == field_info.size,format("'%s'的'%s'字段大小不匹配: %s (D) != %s (C++)",
Type.tupleof[idx].stringof, Type.stringof,
typeof(field).sizeof, field_info.size));
assert(Type.tupleof[idx].offsetof == field_info.offset,
format("'%s'的'%s'的偏移不匹配: %s (D) != %s (C++)",
Type.tupleof[idx].stringof, Type.stringof,
Type.tupleof[idx].offsetof, field_info.offset));
}
}
标::映射
#include <map>
template<typename K, typename V>
class Map {
static Map<K,V>* make () { return new Map<K,V>(); }
V& operator[] (K const& key) { return this->map[key]; }
void insertOrAssign(const K& key, const V& value) {
this->map.insert_or_assign(key, value);
}
std::map<K, V> map;
};
// 显式实例化
template struct Map<char const*, int>;
标::映射
在D
端:
extern(C++, class):
struct Map (Key, Value) {
extern(D) void opIndexAssign (Value value, const Key key)
{
this.insertOrAssign(key, value);
}
static Map* make ();
ref Value opIndex (ref const Key key);
private void insertOrAssign(const ref Key, const ref Value);
}
应该变这样:
#include <map>
template class std::map<char const*, int>;
//变为
import core.stdcpp.map;
alias MyMap = map!(const(char)*, int);
绑定std
当前
在core.stdcpp
,将转移
到另一个库
.
allocator, array, vector, string, exception, memory, string_view...
,但无map
.
C++包装器代码
序号 | 优点 |
---|---|
1 | 你需要它(来实例化 模板) |
2 | 你最强大的盟友 |
3 | 按ref 传递 |
4 | 奇怪的C++ 代码:包装throw,返回值 等… |
逐步替换C++
替换单个函数
很容易,替换方法
也很简单,清除依赖/提高
代码质量的简单方法
:
整合C++的特征
extern(C++, [class|struct])
extern(C++, ident|expression)
core.attributes : gnuAbiTag
pragma(mangle, str_or_decl, [str])
__traits(getTargetInfo, "something")
及,复制构造器/内部指针(串)
,及DWARF
异常处理.
哪些有用
序号 | 有用点 |
---|---|
1 | 良好的C++ 代码 |
2 | 开始就有的额外C++ 代码 |
3 | 显式 模板实例化或包装器 |
4 | 按ref/指针 传递 |
5 | 手工制作,及基本用户类型 |
6 | -preview=in(constT&) |
7 | 不使用DMD |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现