d中绑定C++的常
原文
Jan:在D中有个extern(C++)
类:
extern(C++) class A
{
~this();
// ...
}
及一个带const
引用A的函数:
void CppFunc(const A& arg);
我该如何在D中绑定它?
extern(C++) void CppFunc(A arg); // 按A*传递
extern(C++) void CppFunc(ref const(A) arg);
// 按'A const * const &'传递
按D中构
声明解决了其他类
类似问题,但仅针对无虚函数类
.我现在有个确实需要在D端用类
的C++类
,把对象
传递给C++
时遇到了问题.
evilrat:
可用extern(C++,struct)
告诉编译器
按构/类
混杂.
extern (C++, struct) //即使它是类,也用构混杂
class SomeDClass
{
...
}
试了,但不管用,因为似乎D是按D中而不是C++
中类/构
来决定如何传递对象
.因此,即使按你的改了,仍按前面指针传递
.
Ola
,这有用吗?
extern(C++) class _A {}
extern(C++) struct A {}
extern(C++) void CppFunc(ref const(A) arg);
void func(_A a){
CppFunc(*cast(A*)a);
}
evilrat:
仅当该构与类
内存布局匹配
时,唯一潜在问题是C++
端的构造器
.
此外,C++
类可能有非0初化
且由于对齐
有字节间隙
,这会破坏
,包括(默认)等价运算符
等.要非常小心.
ola:是的,我不想用它,也许手动混杂更好,但仍很痛苦.常 A&
在C++API
中很普遍,真应开箱即用的支持它.只需在D规范
中加个如ref const(@deref(A))
的解引用类型构造器
.
jan
:我完全同意.这种模式在C++
中非常普遍,我很惊讶D无法做到这一点.与C++
链接的整个想法
是轻松互操作,小摩擦,高性能
.
对按参数或返回类型
传递的类,更改混杂
为尾常
,但会破坏许多代码.提案,加解引用类型构造器
提案也允许尾常
类.
jan:解引用,D
尝试对C++
应用类指针/引用
语义,即使它可按不同方式.'Deref'
只能解决该(常见)问题.但是,在C++
中,按值的类
也很常见.也许可给D编译器
提供提示.
如果我有如下C++
代码:
class A { ... };
void AsValue(A value);
void AsPtr(A* value);
void AsConstPtr(const A* value);
void AsRef(A& value);
void AsConstRef(const A& value);
我认为,目前只能绑定到"AsPtr
“和”AsConstPtr
"形式函数.如果按D中构声明A
,可绑定到其他,但有时不行.
在D
中,如何用"构
"关键字按值类型
传递给函数?
extern(C++) class A { ... }
extern(C++) void AsValue(struct A value);
extern(C++) void AsPtr(A value); // 同上
extern(C++) void AsPtr(struct A* value); // 同上
extern(C++) void AsConstPtr(const(A) value);
extern(C++) void AsConstPtr(const(struct A*) value); // 同上
extern(C++) void AsRef(ref struct A value);
extern(C++) void AsConstRef(const(ref struct A) value); // 同上
这里"构
“关键字告诉编译器与C++
一样,按值类型
对待A,因此与C++同样
应用指针,常量和引用语义
.此外,如果遇到纯”A 构
",编译器需要类似构在栈上
创建对象副本
,并传递给C++
(可能会修改临时对象
).实现可能难,但始终可传递类
给C++
.额外好处不应改变
现有行为,因此无破坏.
前面cast
方法不行,
tim:最简单方法可能是手动设置混杂:
pragma(mangle, "_Z7CppFuncRK1A")
extern(C++) void CppFunc(const A arg);
//针对Itanium,林操,对窗口不一样.
tim:D与C++
交互方式是合理且非常有用
的.链接兼容性
大有帮助.
与C++
不同,D变量默认有线程本地存储
,要链接C++
全局变量,要在D中用__gshared(类似共享,但由程序员(而非编译器)保证同步)
的存储修饰符
,
module a;
struct Foo {}
extern(C++)
__gshared Foo globalFoo;
我已成功使用了来自DLL
的全局变量.DMD
现在也测试了C++DLL
:地址
在C++
中应该这样声明变量:
__declspec(dllexport) int value;
然后D这样访问它:
extern (C++) export extern __gshared int value;
你有你问题的测试用例吗?
jan:
class Test
{
public:
__declspec(dllexport) static int var;
};
//也试了不带extern(C++),及不带export
int Test::var = 42;
//D端
extern(C++, class) struct Test
{
extern (C++) export extern __gshared int var;
}
dmd
报错:
error LNK2019: unresolved external symbol "public: static int Test::var" (?var@Test@@2HA)
我检查了DLL
定义符号的.exp
文件,名字完全相同.是的,我大致正确链接到该DLL
,DMD
链接该DLL
中其他符号
也很好.
tim:我可重现你的问题.如果var
是静
的,似乎可工作:
extern(C++, class) struct Test
{
extern (C++) export extern static __gshared int var;//加个静
}
无静就无法工作,这可能是个错误.文档说也可应用__gshared
至成员变量和局部变量
.此时,__gshared
除了全局共享而非线程本地共享
,与静
等价.
extern export __gshared static int var;
//`外`时为啥要导出?
确实工作了.__gshared
在D
中为静
?
H.S:
不.此时,静
:生命期是模块
生命期.默认,静态变量
在TLS
中,有实例化它的线程
生命期(且每线程一实例).
要用__gshared
来使编译器按C/C++意义
对待全局变量
,即所有线程中只有1个实例
.C 静==D __g共享
.
tim:我同意__gshared
应暗示静态
.可能是编译器
错误.
不带导出
用外
,仅适用于(在Windows
上)静态链接.与在C++
中的__declspec(dllexport)
一样,不带外
的导出会导出其他变量
.与__declspec(dllimport)
一样,组合导出
和外
来导入变量.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现