向 c# 公开 c++/CLI 模板化包装器

expose c++/CLI templated wrapper to c#

我目前正在使用可视化编辑器来构建有限状态机。核心是 c++,因为构建的 FSM 将在游戏中 运行。编辑器是c#。我能够运行一个 CLI 包装器,这样我就可以在 C# 端构建我需要的一切。 我想做的最后一件事是能够将模板化 class 公开给 c#。

我首先创建了一个托管 class:

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 中以防万一,我什至尝试在 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: 我知道没有释放内存的析构函数,这只是一个为了保持示例简短的虚拟测试。

如果您实现模板 class 的完整子 class,那应该可以解决问题。您将需要实现所有构造函数,但只是作为基础 class 构造函数的传递;没有实际代码。

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)

如您所见,无法在它们所在的程序集之外访问托管模板。基本上这个想法是将托管模板公开为可以跨程序集边界发送的通用接口。

所以在你的情况下,你会想创建一个 ITestTemp,像这样...

generic<typename T> public interface class ITestTemp
{
  public:
    TestTemp(T val);
}

这是您将跨程序集导出的接口。现在您必须将托管模板转换为该通用接口才能使用继承,具有以下签名(为简单起见省略内部)

templace<typename T> ref class TestTemp : ITestTemp<T>

一旦你有了它,现在你将不得不做 "compiler's work"(对于常规 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...
    }
}

我希望解释得足够好,如果没有让我知道。