我有一个 utils.h 和一个 utils.cpp,其中包含实用程序函数,它们都被公共(public)命名空间包围。当我直接将 utils.h 包含到项目中时,我可以访问所有这些功能。
utils.h:
namespace Utils
{
template <class T>
T interpolationLinear ( array<T,1>^ i_aData,
double i_dRatio)
{
array<T,1>^ aPart = gcnew array<T,1>(2);
aPart[0] = i_aData[0] * (1 - i_dRatio);
aPart[1] = i_aData[1] * (i_dRatio);
return aPart[0] + aPart[1];
}
...
double parseToDouble (System::String ^sValue); // defined in cpp
}
现在我正在创建几个托管 DLL,实用程序函数应该成为其中之一。问题:我无法再访问 DLL/程序集中的函数。似乎只有类才能构建 DLL 接口(interface)。
然后,我将命名空间更改为公共(public)引用类并将函数设为静态,因此我可以重新访问某些函数:
utils.h:
public ref class Utils
{
template <class T>
static T interpolationLinear (array<T,1>^ i_aData,
double i_dRatio) // NO ACCESS
// like above
...
static double parseToDouble (System::String ^sValue); // CAN BE ACCESSED NOW
};
但是为什么我不能调用模板函数呢?这里出了什么问题?
最佳答案
您遇到了 C++ 模板的众所周知的限制,它们没有外部链接。在 C++ 中,您可以通过将模板定义放入 .h 文件中并在其他 C++ 项目中 #include 该文件来解决该问题。这当然在这里不起作用,托管编译器不知道有关 .h 文件的 bean,只有 C++ 编译器可以解析它们。
这将是 .NET Framework 的一个主要限制,它支持许多不同的语言,并且 C++ 和 Java 中使用的模板的类型删除实现在实践中效果不佳。换句话说,像 VB.NET 这样的语言无法使用用 C# 等编写的模板。
因此他们采取了一种完全不同的方法,称为“具体化泛型”。与类型删除的最大区别在于泛型方法是在运行时而不是编译时创建的。或者换句话说,托管编译器创建了该方法的“千篇一律”模型,它在运行时即时编译时变得具体化。千篇一律的代码与任何语言都相同,以 MSIL 表示,因此任何支持泛型的语言都可以调用它。
在 C++/CLI 中,您只需将模板替换为泛型即可使用这种泛型。通常需要一些额外的语法来使用 where 关键字设置类型约束,但在您的情况下只需替换就足够了。
这实际上不起作用,您现在会发现特定于具体化泛型的限制。编译器会提示 * 运算符。该运算符没有通用版本。根本问题是只有少数实际类型具有此运算符。在.NET中只有int、long、float和double有它。或者换句话说,当您调用该方法时,可以使用的实际 T 很少。
值得注意的是,您实际上可以在代码中的更多类型上使用该运算符。例如,它可以很好地乘以字节或十进制。但这需要不平凡的转换,首先必须将 byte 提升为 int。对于十进制,它需要发现该类型具有专用的operator*()
重载。这些不平凡的转换很容易由知道类型的编译器完成,但它们不能用编译器为泛型方法生成的千篇一律的代码来表达。所以根本不支持它。
长话短说,你不能使这个方法变得通用。没什么真正的问题,确实很少有你会使用它的 T,而且方法很小。因此,只需提供该方法的重载,问题就解决了。
关于.net - 程序集中的模板函数不可见,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20049313/