Лучший обходной путь для ошибки компилятора C2158: make_public не поддерживает нативные типы шаблонов

StackOverflow https://stackoverflow.com/questions/4121249

  •  29-09-2019
  •  | 
  •  

Вопрос

У меня есть два DLL C ++ /CLI (т.е. скомпилирован с /clr), где A.DLL ссылки B.DLL. В сборке B у меня есть метод, getmgdclassb, я хотел бы позвонить из Ассамблеи А. Вот код в Ассамблеи 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 :: evector. В сборке 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

Причина, по которой я хотел добавить эту прагму, заключается в том, что нативные типы являются частными для сборки по умолчанию. Если я удалю прагму, я получу следующую ошибку (как и ожидалось):

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

Поскольку тип экземпляра шаблона std::vector<B::NativeClassB *> является частным для Ассамблеи.

Попытка решений

1. Используйте void *, Break Type Безопасность:

Изменить метод, 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, поскольку (а) оно не представляет никаких проблем с производительностью, и (б) я буду делать это только в нескольких случаях. Мне не нравится потерять безопасность типа, но это кажется оправданным, учитывая текущий недостаток в способности компилятора делать нативные типы экземпляров -типов.

Вопрос:

Есть ли лучше?

Связанный вопрос:

C ++ CLI Ошибка C3767: Функция (ы) кандидата не доступна

Это было полезно?

Решение

Я не знаю, как экспортировать этот тип. Если у вас должна быть такая подпись функции, я бы склонялся в направлении использования сочетания управляемого и нативного экспорта (управляемые функции с использованием нативных типов в любом случае не могут использоваться другими языками) и, возможно, используйте задержку загрузки при вызове родных Экспорт, чтобы у вас была возможность улавливать ошибки, найти сборку обычным способом .NET.

Но ваша конкретная функция может быть проблематичной, поскольку она использует как управляемые типы, так и сложные нативные типы в подписи.

В целом, наилучшая практика состоит в том, чтобы вообще не проходить нативные классы C ++ по границам DLL вообще, поскольку это заставляет вас для одного нарушения правил определения.

Для этой конкретной ситуации мое предложение состоит в том, чтобы сделать обертку, которая реализует ICollection. Отказ Это лечит проблему, как и ваше решение № 2, даже не нужно копировать все элементы в новую структуру данных.

Другие советы

Я получил решение от Майка Данеса на другом форуме:

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

По сути, решение состоит в том, чтобы создать собственную обертку (назовите ее VectorOfnativeB) в сборке B, которая удерживается на указателе или ссылке на вектор Std ::. Экспорт VectorOfNativeB и делает его публичным виденным. Метод изменения getMgdClassb для получения указателя или эталона VectorOfNativeB.

опубликовал это здесь для будущей ссылки и чтобы увидеть, есть ли у кого -нибудь есть какие -либо комментарии по поводу этого решения].

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top