我目前正在开发一个可视化编辑器来构建有限状态机。核心是c ++,因为构建的FSM将在游戏中运行。编辑器是c#。我能够获得一个CLI包装器,所以我可以在c#端构建我需要的所有东西。 我要做的最后一件事是能够将模板化的类暴露给c#。
我首先创建了一个托管类:
template <typename T>
public ref class TestTemp
{
private:
ClassToWrap<T>* m_val;
public:
TestTemp(T val) :
{
m_val = new ClassToWrap<T>();
}
}
然后,因为模板是在编译时生成的,所以我强制生成具有模板特化的类型。
template ref class FSMWrapper::TestTemp<float>;
我尝试了几个地方的专业化,cpp,header,也是为了以防万一,我甚至尝试了在main中的特定实例化:
FSMWrapper::TestTemp<float> t(10.0f);
我甚至试图明确告诉导出符号,就像我在常规c ++中那样做但是编译器抱怨我不能用托管类型做。
毕竟,我没有设法让符号出现在c#名称空间中,(其他一切都出现了,所以是的,包装器按预期工作)。
此外,如果我在包装器中删除模板并将其称为TestTempFloat并在内部强制实现float的实例化。
public ref class TestTempFloat
{
private:
ClassToWrap<float> m_val;
public:
TestTempFloat(float val) :
{
m_val = new ClassToWrap<float>();
}
};
我想做什么,甚至可能吗?通过谷歌搜索看起来像是,但人们只是说,将其包装在CLI类型中并强制生成符号。 如果可能我做错了什么?
如果不可能,我只需要手动进行专门的包装,不是很漂亮,但我知道它有效。
我还尝试将其包装在通用而不是模板中,但之后我无法将T泛型类型作为模板类型提供。
PS:我知道没有一个析构函数来释放内存,这只是一个虚拟测试来保持示例简短。
答案 0 :(得分:2)
如果你实现了模板类的完整子类,那应该可以解决问题。您将需要实现所有构造函数,但只是作为基类的构造函数的传递;没有实际的代码。
public ref class TestTempFloat : TestTemp<float>
{
TestTempFloat(float val) : TestTemp(val) { };
};
如果你有很多这些,你可以使用预处理器:
#define IMPLEMENT_TESTTEMP(namesuffix, type) \
public ref class TestTemp ## namesuffix : TestTemp<type> \
{ \
TestTemp ## namesuffix(type val) : TestTemp(val) { }; \
};
IMPLEMENT_TESTTEMP(Float, float)
IMPLEMENT_TESTTEMP(Double, double)
IMPLEMENT_TESTTEMP(Int, int)
答案 1 :(得分:1)
如您所见,托管模板无法在它们所在的程序集之外访问。基本上,我们的想法是将托管模板公开为可以跨程序集边界发送的通用接口。
所以在你的情况下,你会想要创建一个ITestTemp
,就像这样......
generic<typename T> public interface class ITestTemp
{
public:
TestTemp(T val);
}
这是您将跨程序集导出的界面。现在您必须将托管模板转换为该通用接口,以便您可以使用继承,具有以下签名(为简单起见省略内部)
templace<typename T> ref class TestTemp : ITestTemp<T>
一旦你有了这个,你将不得不做“编译工作”(通常只是为常规C ++模板自动处理),以便它可以在两者之间进行转换。因此,您必须创建一个工厂方法,该方法将创建您要查找的特定实例。它看起来像这样
public ref class TestTempFactory
{
public:
generic<typename T> static ITestTemp<T>^ Create()
{
if (T::typeid == String::typeid)
{ return (ITestTemp<T>^) gcnew TestTemp<String>(); }
//more cases as needed...
}
}
如果不让我知道的话,我希望能够解释得很清楚。