原文 Jan:在D中有个extern(C++) 类:
extern(C++) class A
{
~this();
}
及一个带const 引用A的函数:
void CppFunc(const A& arg);
我该如何在D中绑定它?
extern(C++) void CppFunc(A arg);
extern(C++) void CppFunc(ref const(A) arg);
按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);
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;
};
int Test::var = 42;
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) 一样,组合导出 和外 来导入变量.
|