C++/CLI от typedef std::function к управляемому делегату

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

typedef std::function<void(const std::string &, Float)> ProgressCallback;
class MeshGenerator{
public:   
ProgressCallback progress;
/// <summary>
/// set callback
/// </summary>
/// <param name = "_callback"></param>
inline void SetCallback(ProgressCallback _callback){ this-> progress =_callback; }   
};

Теперь мой код управления упрощен:

public delegate void CallbackDelegate(String^ cap, float data);
public ref class MeshWrapper
{

private:
MeshGenerator *gen;
public:
[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
CallbackDelegate^ _Delegate;
inline MeshWrapper(){ 
  this->gen = new MeshGenerator();
  _Delegate = gcnew CallbackDelegate(this, &MeshWrapper::Progress);
  auto ptr = Marshal::GetFunctionPointerForDelegate(_Delegate).ToPointer();
  ProgressCallback *p = static_cast<ProgressCallback*>(ptr);
  this->gen->SetCallback(*p);
}   
inline void Progress(String^ cap, float s){ System::Console::WriteLine(cap + s);}
};

этот код компилируется, но в конструкторе MeshWrapper статическое приведение ("static_cast<ProgressCallback*>(ptr);") дает мне пустой делегат.

Вероятно, я делаю некоторые концептуальные ошибки. Спасибо за вашу помощь.

обратный вызов на встроенный? ... также std::string не совместим со строкой dotnet

Selvin 10.05.2024 11:10

@Selvin, спасибо за ответ, но я не могу изменить неуправляемый класс... мне нужно найти способ использовать ProgressCallback в управляемом коде..

The Overrider 10.05.2024 11:13

Прошло некоторое время с тех пор, как я писал код на C++, но у вас должна быть возможность создать неуправляемый вспомогательный класс, у которого есть gcroot для вашего meshWrapper. Таким образом, вам не придется полагаться на какие-либо автоматические преобразования.

JonasH 10.05.2024 12:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
55
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы не можете просто привести указатель функции к указателю std::function, вам нужно создать объект std::function:

auto pc = ProgressCallback(reinterpret_cast<void(*)(const std::string &, Float)>(ptr));
this->gen->SetCallback(pc);

В качестве альтернативы можно передать лямбду, которая выполняет прямое приведение и, возможно, исправляет некоторые аргументы:

this->gen->SetCallback([=](const std::string & s, Float f) {
  auto fn = reinterpret_cast<void(*)(const std::string &, float)>(ptr);
  fn(msclr::interop::marshal_as<String^>(s), f);
});

спасибо, я близок к решению проблемы, первый метод работает, но когда мой метод Managed Progress вызывается, строка ^ cap имеет неправильное значение, вероятно, потому, что мне нужно преобразование из std::string в String^... второй не компилируется с этим сообщением: «Локальная лямбда C++ не разрешена в функции-члене управляемого класса»...

The Overrider 10.05.2024 11:57

Спасибо @Botje за помощь, теперь я решил свою проблему следующим образом:

public delegate void CallbackDelegate(std::string& cap, float data);

Я изменил своего делегата обратного вызова в управляемом коде с помощью std::string&.

reinterpret_cast такой же, как и @Botje.

В управляемом метод Progress меняется следующим образом:

void MeshWrapper::Progress(std::string&  cap, float s) {
 // Transform std string in String^!!!!!!
 String^ newSystemString = gcnew String(cap.c_str());   
 // Code that uses newSystemString here :)  
};

Спасибо.

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