学堂 学堂 学堂公众号手机端

d与C++互操作(互操作是什么意思)

lewis 1年前 (2024-03-29) 阅读数 6 #技术


为什么是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 =>
第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​


版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门