编译器错误C2158的最佳解决方法:make_public不支持本机模板类型

时间:2010-11-08 04:23:48

标签: c++-cli compiler-errors pragma

我有两个c ++ / cli dll(即使用/ clr编译),其中A.dll引用B.dll。在程序集B中,我有一个方法,GetMgdClassB,我想从程序集A调用。这是程序集B(B.cpp)中的代码:

namespace B
{
    public class NativeClassB
    {
    public:
        NativeClassB();
        // ... 
    };

    public ref class MgdClassB
    {
    public:
        static MgdClassB ^ GetMgdClassB(const std::vector<NativeClassB *> & vecNativeBs)
        {
            // ...
            vecNativeBs;
            return gcnew MgdClassB();
        }
    };
}

请注意,方法GetMgdClassB采用std :: vector。在程序集A中,我尝试使用以下代码(A.cpp)调用此方法:

namespace B
{
    class NativeClassB;
}

#pragma make_public(std::vector<B::NativeClassB *>)

namespace A
{
    void Foo()
    {
        std::vector<B::NativeClassB *> vecNativeBs;
        B::MgdClassB::GetMgdClassB(vecNativeBs);
    }
}

当我编译A.cpp时,我收到以下错误:

error C2158: 'std::vector<_Ty>' : #pragma make_public directive is currently supported for native non-template types only

我想添加此pragma的原因是因为默认情况下本机类型是程序集的私有。如果我删除了pragma,我会收到以下错误(正如预期的那样):

error C3767: 'B::MgdClassB::GetMgdClassB': candidate function(s) not accessible

因为模板实例化类型std::vector<B::NativeClassB *>对于程序集是私有的。

尝试解决方案

1。使用void *,break type safety:

更改方法GetMgdClassB以获取void *并将std::vector<NativeClassB *>的地址传递给方法。在GetMgdClassB。然后我可以static_cast传入void *std::vector<NativeClassB *> *。当然,这有效,但打破了类型安全。

2。为NativeClassB创建托管包装器,传递托管容器

创建一个托管类,比如ref class NativeClassBWrapper,其唯一目的是挂起对本机NativeClassB的引用。更改GetMgdClassB以获取NativeClassBWrappers的托管容器(例如List<NativeClassBWrapper ^> ^)。这有必要在调用GetMgdClassB之前创建和填充新的托管容器,然后在托管类B中,我必须将其重新打包到本机容器std::vector<NativeClassB *>中(因为B中的代码处理此问题)类型。

目前,我倾向于使用解决方案#1,因为(a)它没有引入任何性能问题,(b)我只会在少数情况下这样做。我不喜欢失去类型安全性,但鉴于当前编译器使本机模板实例化类型可见的能力不足,这似乎是合理的。

问题:

有更好的解决方法吗?

相关问题:

C++ CLI error C3767: candidate function(s) not accessible

2 个答案:

答案 0 :(得分:2)

我不知道有什么方法可以导出这种类型。如果你必须拥有该功能签名,我将倾向于使用托管和本机导出的混合方向(使用本机类型的托管函数无论如何都不能被其他语言使用),并且可能在调用本机时使用延迟加载导出,所以你有机会陷阱错误,以通常的.NET方式找到程序集。

但是您的特定功能可能会有问题,因为它在签名中使用托管类型和复杂的本机类型。

通常,最佳做法是不要在DLL边界之外传递本机C ++类,因为这会为您设置违反One Definition Rule的行为。

对于这种特殊情况,我的建议是创建一个实现ICollection的包装器。这就像你的解决方案#2一样解决问题,而不必将所有元素实际复制到新的数据结构中。

答案 1 :(得分:2)

我在另一个论坛上收到了Mike Danes的解决方案:

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/b43cca63-b0bf-451e-b8fe-74e9c618b8c4/

基本上,解决方案是在程序集B中创建一个本机包装器(称为VectorOfNativeB),它保存指针或对std :: vector的引用。导出VectorOfNativeB并使其公开可见。更改方法GetMgdClassB以获取指针或引用VectorOfNativeB。

[在此发布此信息以供将来参考,并了解此处是否有人对此解决方案有任何意见]。