为c++模板扩展c#代理类
Extend C# Proxy Class for a C++ template
TLDR:我如何在c#中为SWIG访问模板类型"T" ?
假设我在c++中有以下模板类,其中包含一个Validate
函数:
template<typename T>
struct MyTemplateClass
{
bool Validate(T* _in)
{
//...
}
// ... other stuff... MyTemplateClass is also a container for T*
};
假设我为各种对象实例化类:
%template(MyTemplateClassFoo) MyTemplateClass<Foo>
%template(MyTemplateClassBar) MyTemplateClass<Bar>
// etc.
在c#中,我希望Validate
函数也验证内存所有权。无论_in.swigCMemOwn
是true
还是false
,所以我希望c#包装器看起来像这样(对于MyTemplateClassFoo
)
public class MyTemplateClassFoo{
public bool Validate(Foo _in) {
bool ret = _in.swigCMemOwn &&
ModuleCLRPINVOKE.MyTemplateClassFoo_Validate(swigcPtr, Foo.getCPtr(_in));
// SWIGEXCODE stuff
return ret;
}
// ...
}
这里的问题是,如果我想写自己的Validate
函数,我不知道_in
将是什么类型。在Python中,我可以使用feature("shadow")
或pythonprepend
和pythonappend
现在我已经得到了:
- 使用
%csmethodmodifiers MyTemplateClass::Validate "private";
将Validate
设为私有 - 通过
%rename(InternalValidate, fullname=1) "MyTemplateClass::Validate";
将Validate
重命名为InternalValidate
- 使用
%typemap(cscode)
添加一个将调用InternalValidate
的新函数:
%typemap(cscode) MyTemplateClass %{
public bool Validate(/*Type?*/ _in)
{
return _in.swigCMemOwn && InternalValidate(_in);
}
%}
但是我不知道我应该为/*Type?*/
指定什么。我试过T
, T*
, typemap(cstype, T)
,但似乎没有像$csargtype
这样的特殊swig变量,我可以使用。
我试着看看SWIG如何包装std::vector
,似乎他们正在定义一个宏,然后以某种方式调用它的每个专门化的向量?我想我可以接受,但我不喜欢。
为了完成这些示例,我创建了以下头文件:
template<typename T>
struct MyTemplateClass
{
bool Validate(T* _in)
{
return false;
}
// ... other stuff... MyTemplateClass is also a container for T*
};
struct Foo {};
好消息是,实际上有可能生成您所要求的代码,比您尝试过的代码简单得多。我们可以使用只匹配Validate
的csout类型映射,这样就可以了:
%module test
%{
#include "test.hh"
%}
%typemap(csout, excode=SWIGEXCODE) bool Validate {
// referring to _in by name is a bit of a hack here, but it works...
bool ret = _in.swigCMemOwn && $imcall;$excode
return ret;
}
%include "test.hh"
%template(MyTemplateClassInt) MyTemplateClass<int>;
%template(MyTemplateClassFoo) MyTemplateClass<Foo>;
为了完整起见,让我们看看最初提出的问题。首先,让我们通过使MyTemplateClass
实际上不是一个模板(即注释出测试的第一行)来简化事情。(并在某处为T添加一个类型定义)。
在这种情况下,您尝试做的工作相当多,使用$typemap(cstype, T)
在SWIG编译时查找用于给定类型的c#类型:
%module test
%{
#include "test.hh"
%}
%typemap(cscode) MyTemplateClass %{
public bool Validate($typemap(cstype, T) in) {
return in.swigCMemOwn && InternalValidate(in);
}
%}
%rename(InternalValidate) Validate;
%include "test.hh"
然而,当我们再次将其还原为模板时,生成的代码不正确,生成的Validate
是:
public bool Validate(SWIGTYPE_p_T in)
发生这种情况是因为SWIG(至少从Ubuntu 14.04开始的3.0)在上下文中没有意识到关于T的任何事情-模板替换没有正确发生。我不太确定这是一个错误还是预期的行为,但无论如何,这对我们来说都是一个问题。
有趣的是,如果你愿意在模板的定义中编写cscode类型映射,SWIG看到的替换确实有效:
%module test
%{
#include "test.hh"
%}
%rename(InternalValidate) Validate;
template<typename T>
struct MyTemplateClass
{
bool Validate(T* _in)
{
return false;
}
// ... other stuff... MyTemplateClass is also a container for T*
%typemap(cscode) MyTemplateClass %{
public bool Validate($typemap(cstype, T) in) {
return in.swigCMemOwn && InternalValidate(in);
}
%}
};
struct Foo {};
%template(MyTemplateClassInt) MyTemplateClass<int>;
%template(MyTemplateClassFoo) MyTemplateClass<Foo>;
在上面的接口中,T
的类型被正确地替换到输出中。所以如果你愿意接受。i文件和你在库中使用的真正的头文件之间的复制,那就足够了。您还可以编辑头文件本身,并将SWIG和c++混合到其中,即下面修改过的测试。Hh得到相同的结果:
template<typename T>
struct MyTemplateClass
{
bool Validate(T* _in)
{
return false;
}
// ... other stuff... MyTemplateClass is also a container for T*
#ifdef SWIG
%typemap(cscode) MyTemplateClass %{
public bool Validate($typemap(cstype, T) in) {
return in.swigCMemOwn && InternalValidate(in);
}
%}
#endif
};
struct Foo {};
这是有效的,因为SWIG定义了预处理器宏SWIG,但它不会在正常的c++编译过程中定义,所以一切都很好。就我个人而言,我不喜欢这样——我宁愿让c++和SWIG位在逻辑上分开,有一个干净的边界。
然而,如果你不愿意复制像那样,不能/不会简单地编辑头文件,所有都不会丢失。我们可以(ab)使用%extend
让我们做同样的事情:
%module test
%{
#include "test.hh"
%}
%rename(InternalValidate) Validate;
%include "test.hh"
%extend MyTemplateClass {
%typemap(cscode) MyTemplateClass %{
public bool Validate($typemap(cstype, T) in) {
return in.swigCMemOwn && InternalValidate(in);
}
%}
}
%template(MyTemplateClassInt) MyTemplateClass<int>;
%template(MyTemplateClassFoo) MyTemplateClass<Foo>;
又成功了
最后一个解决方法是,如果你在模板中有一个typedef,它只使用T,例如:template<typename T>
struct MyTemplateClass {
typedef T type;
//...
然后下面的工作,引用类型定义为$1_basetype::type
:
%module test
%{
#include "test.hh"
%}
%rename(InternalValidate) Validate;
%typemap(cscode) MyTemplateClass %{
public bool Validate($typemap(cstype, $1_basetype::type) in) {
return in.swigCMemOwn && InternalValidate(in);
}
%}
%include "test.hh"
%template(MyTemplateClassInt) MyTemplateClass<int>;
%template(MyTemplateClassFoo) MyTemplateClass<Foo>;
因此,即使简单的方法看起来应该工作似乎没有,仍然有很多选项开放,以达到我们需要的结果
- 代理对象的常量正确性
- 是否可以通过C++扩展强制多个python进程共享同一内存
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 如何将这个C++哈希表转换为动态扩展和收缩,而不是使用硬设置的最大值
- 扩展光电二极管探测器以支持多个传感器
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- C++中的VLA,扩展名为std=C++11
- OpenGL 和 GLM 矩阵无法正确扩展,总是按比例缩小
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- C++返回 Numpy 数组的 Python 扩展模块
- 扩展可变参数模板中的变量名称
- 具有所表示类的相同构造函数签名的代理类模板
- 扩展C++生成的代码的模板参数类型名称
- 我想通过带有C++和Python的插件创建一个可扩展的应用程序
- VSCode IntelliSense无法识别SDL框架的SDL_image扩展库
- 将元组类型扩展为可变参数模板?
- 如何按文件扩展名引用文件夹中的文件
- Windows Server 2012上的SNMP扩展代理无法连接到需要数据的端口
- 为c++模板扩展c#代理类
- 与开发SNMP扩展代理DLL相关