编译器错误 C2158 的最佳解决方法:make_public 不支持本机模板类型 [英] Best workaround for compiler error C2158: make_public does not support native template types

查看:33
本文介绍了编译器错误 C2158 的最佳解决方法:make_public 不支持本机模板类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have two c++/cli dlls (i.e. compiled with /clr) where A.dll references B.dll. In assembly B, I have a method, GetMgdClassB, I'd like to call from assembly A. Here is the code in assembly 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) 调用此方法:

Notice that the method GetMgdClassB takes a std::vector. In assembly A, I attempt to call this method with the following code (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 时,出现以下错误:

When I compile A.cpp, I get the following error:

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

我想添加这个 pragma 的原因是因为默认情况下本机类型对于程序集是私有的.如果我删除编译指示,我会收到以下错误(如预期):

the reason I wanted to add this pragma is because native types are private to the assembly by default. If I remove the pragma I get the following error (as expected):

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

因为模板实例化类型 std::vector 是程序集私有的.

since the template instantiation type std::vector<B::NativeClassB *> is private to the assembly.

更改方法,GetMgdClassB 取一个void * 并将std::vector 的地址传递给方法.在 GetMgdClassB 中.然后我可以将 static_cast 传入的 void * 传递给 std::vector*.这当然有效,但破坏了类型安全.

Change the method, GetMgdClassB to take a void * and pass the address of the std::vector<NativeClassB *> to the method. In GetMgdClassB. I can then static_cast the passed in void * to std::vector<NativeClassB *> *. This, of course, works, but breaks type safety.

创建一个托管类,比如 ref class NativeClassBWrapper,它的唯一目的是保留对本地 NativeClassB 的引用.更改 GetMgdClassB 以获取 NativeClassBWrappers 的托管容器(例如 List ^).这样做的缺点是必须在调用 GetMgdClassB 之前创建并填充新的托管容器,然后在托管类 B 中,我必须将其重新打包到本机容器 std::vector(因为 B 中的代码处理这种类型.

Create a managed class, say ref class NativeClassBWrapper who's sole purpose is to hang on to a reference to the native NativeClassB. Change GetMgdClassB to take a managed container of NativeClassBWrappers (e.g. List<NativeClassBWrapper ^> ^). This has the downside of having to create and populate a new managed container prior to calling GetMgdClassB, and then within managed class B, I have to repackage it into the the native container std::vector<NativeClassB *> (since the code in B deals with this type.

目前,我倾向于使用解决方案 #1,因为 (a) 它不会引入任何性能问题,并且 (b) 我只会在少数情况下这样做.我不喜欢失去类型安全性,但考虑到当前编译器无法使原生模板实例化类型可见,这似乎是合理的.

Currently, I'm leaning toward going with Solution #1, since (a) it doesn't introduce any performance concerns and (b) I'll only be doing this in a few cases. I don't like losing the type safety, but it seems justifiable given the current deficiency in the compiler's ability to make native template instantiation types visible.

有更好的解决方法吗?

C++ CLI 错误 C3767:无法访问候选函数

推荐答案

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

I'm not aware of any way to export that type. If you have to have that function signature, I would lean in the direction of using a mix of managed and native exports (managed functions using native types can't be consumed by other languages anyway), and maybe use delay loading when calling the native exports so you have a chance to trap errors finding the assembly in the usual .NET way.

但是您的特定函数可能有问题,因为它在签名中同时使用了托管类型和复杂的本机类型.

But your particular function may be problematic since it uses both managed types and complex native types in the signature.

一般来说,最好的做法是根本不要跨 DLL 边界传递本机 C++ 类,因为这会让您违反单一定义规则.

In general, the best practice is to not pass native C++ classes across DLL boundaries at all, since this sets you up for One Definition Rule violations.

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

For this particular situation, my suggestion is to make an wrapper that implements ICollection. That cures the problem just like your solution #2, without ever having to actually copy all the elements into a new data structure.

这篇关于编译器错误 C2158 的最佳解决方法:make_public 不支持本机模板类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆