【问题标题】:Mapping of C++ specific features to C++/CLI将 C++ 特定功能映射到 C++/CLI
【发布时间】:2016-07-29 08:46:44
【问题描述】:

我正在用 C++/CLI (VS 2015) 为给定的 C++ 代码编写一个包装器,以便最终使用 C# 中生成的托管 dll。因此,我创建了一个调用本机类的托管类。由于返回 unique_ptr 的工厂方法,此本机类链接到给定的 C++ 代码。

现在我卡住了,因为 C++ 代码有一个回调:

Callback(std::function<void(const Result &>)  

结果是类型

std::vector<std::pair<float, float>> 

问题:

  1. 如何在 C++/CLI 中映射回调参数std::function?
  2. 我必须在哪里以及如何转换 C++ 结果结构(对向量) 到 .NET 数据结构(元组列表) 就在 C# 中访问它的回调而言?

  3. 是否可以编写映射到非托管数据结构(向量)的 lambda 表达式(使用 .NET 集合)?

    unsigned int cnt = 0;
    
    nativeClass->Callback([&cnt] (const Result &v) { 
     auto it = d::max_element(v.begin(), v.end(), 
          [](const Pair &a, const Pair &b) {
               return a.second < b.second;
          });
    
          // do something with iterator it
          // …
    
          cnt++;
    });
    

    因此我是否必须编写 lambda 表达式包装器?

【问题讨论】:

    标签: c# c++ lambda unmanaged managed


    【解决方案1】:

    我会稍微改一下你原来的问题,以更好地适应我提出的解决方案:

    1. 如何将 C# 方法包装为非托管 C++ std::function&lt;&gt; 以用作回调?
    2. 如何将回调方法的数据从 C++ (std::vector&lt;std::pair&lt;&gt;&gt;) 转换为 C# (List&lt;Tuple&lt;&gt;&gt;)?
    3. 是否可以使用包含捕获变量的 C# lambda 表达式作为回调方法?

    请参阅下面的解决方案。请记住,它并不漂亮,并且不会进行任何错误或资源处理。它对上述问题的回答如下(Inner 是您要包装的给定 C++ 类):

    1. 回调方法可以作为 C# Action&lt;List&lt;Tuple&lt;&gt;&gt;&gt; 提供(参见Middle::SetCallback)。它被包装方法Middle::WrapCallback 调用。这又可以编组为提供给内部类的非托管函数指针(请参阅构造函数)。
    2. 我不知道任何集合的编组助手,所以这只是通过复制相应的(假设是只读的)数据结构来完成的(参见Middle::WrapCallback)。 Middle::DoCallback 只是用来触发外部回调,所以它需要反向进行转换。
    3. 当然可以,但这完全取决于使用此包装器的 C# 客户端代码。
    using namespace System;
    using namespace System::Collections::Generic;
    using namespace System::Runtime::InteropServices;
    
    namespace Wrapper {
        delegate void CallbackPointer(const Result &data);
        typedef void(*UnmanagedPointer)(const Result &data);
    
        Middle::Middle()
        {
            instance = new Inner();
    
            CallbackPointer^ managed = gcnew CallbackPointer(this, &Middle::WrapCallback);
            IntPtr stubPointer = Marshal::GetFunctionPointerForDelegate(managed);
            UnmanagedPointer UnmanagedCallback = static_cast<UnmanagedPointer>(stubPointer.ToPointer());
    
            instance->SetCallback(UnmanagedCallback);
        }
    
        void Middle::SetCallback(Action<List<Tuple<float, float>^>^>^ callback)
        {
            handler = callback;
        }
    
        void Middle::DoCallback(List<Tuple<float, float>^>^ data)
        {
            Result *buffer = new Result();
    
            for (int i = 0; i < data->Count; i++)
            {
                std::pair<float, float> *el = new std::pair<float, float>(data[i]->Item1, data[i]->Item2);
                buffer->push_back(*el);
            }
    
            instance->Callback(*buffer);
        }
    
        void Middle::WrapCallback(const Result &data)
        {
            List<Tuple<float, float>^>^ buffer = gcnew List<Tuple<float, float>^>();
    
            for (Result::size_type i = 0; i < data.size(); i++)
            {
                buffer->Add(Tuple::Create(data[i].first, data[i].second));
            }
    
            handler->Invoke(buffer);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 1970-01-01
      • 2012-02-13
      • 2017-01-12
      • 1970-01-01
      相关资源
      最近更新 更多