Вызов методов класса C ++ в MEX из MATLAB

У меня есть набор DLP, который мне нужно контролировать через MATLAB с помощью API C ++.

Скажем, у меня есть функции / методы, использующие C / C ++ для {load_data, load_settings,display_data} в mex-файле с именем dlp_controller.cpp / .c.

Я знаю, что могу позвонить dlp_controller(); с MATLAB.

Есть ли способ, которым я могу вызвать метод этого mex из MATLAB напрямую?

Скажем, мой dlp_controller.cpp mex выглядит так:

class dlp{ ... }
dlp::dlp{ ... }
dlp::load_data{ ... }
dlp::load_settings{ ... }
dlp::display_data{ ... }

void mexFunction(int nlhs, mxArray *[],int nrhs, const mxArray *prhs[]{ ... }

Могу ли я как-то вызвать методы, такие как dlp_controller.load_data из MATLAB? ПРИМЕЧАНИЕ: Обходной путь может быть отправить переменную dlp_controller и вызвать функцию внутренне, используя это и переданные данные.

3

Решение

AFAIK, нет простого способа сделать это, потому что mexFunction интерфейс скорее плоский. Тем не менее, я думаю, что есть несколько способов, которые помогут вам приблизиться. Выберите лучший в зависимости от ваших потребностей.

  1. Самый простой — создать глобальный экземпляр dlp класс в вашей функции mex. Заставьте первый параметр функции mex вызвать строку, которая указывает, какую функцию-член глобального объекта следует вызывать. Очевидным недостатком является то, что вы превратили свою функцию mex в синглтон.

  2. Если вам нужно больше, чем один dlp Например, вы можете создать глобальный контейнер в функции mex, std::map<std::string, dlp> например, а затем обратиться к каждому dlp экземпляр по какому-то имени из MATLAB. Например, чтобы создать новый экземпляр, вы должны вызвать функцию mex с именем, которое еще не существует в map, Затем вы можете вызвать mex-функцию с этим именем, строкой, указывающей, какую функцию-член вызывать, и любыми параметрами, передаваемыми в функцию-член. Также установите некоторые соглашения, по которым вы можете стереть dlp экземпляр из map,

  3. Аналогично второму решению, вместо именования dlp случаи, когда вы могли бы вернуться ручки каждому экземпляру. Например, создать глобальный std::set<dlp *> и когда у вас есть функция mex, создайте новый dlp Например, добавьте его в set и вернуть копию указателя на выделенный объект в MATLAB (вставьте его в скалярную переменную типа mxUINT64_CLASS). Последующие вызовы для вызова функций-членов этого объекта справиться переменная в функцию mex из MATLAB, вы соответствующим образом преобразуете ее в файл mex, находите ее в set и вызывать функции-члены.

Ни один из этих методов не особенно хорош, но это единственный известный мне способ вызова функций-членов класса C ++ из файла mex.

6

Другие решения

Возможно, вы захотите взглянуть на это представление в MATLAB Central. Насколько я знаю, это демонстрирует наилучшую практику, разработанную по совету группы новостей от многих, включая MathWorkers.

http://www.mathworks.co.uk/matlabcentral/fileexchange/38964-example-matlab-class-wrapper-for-a-c++-class

4

Проще всего спроектировать оболочку MEX, которая хранит экземпляр объекта класса, и отправить вызов в этот двоичный файл MEX. Я сделал библиотеку для тех, кто пытается разработать MEX-оболочку на C ++.

https://github.com/kyamagu/mexplus

Вот быстрый фрагмент.

// C++ class to be wrapped.
class Database;
// Instance session storage.
template class mexplus::Session<Database>;
// Constructor.
MEX_DEFINE(new) (int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
InputArguments input(nrhs, prhs, 1);
OutputArguments output(nlhs, plhs, 1);
output.set(0, Session<Database>::create(
new Database(input.get<std::string>(0))));
}
// Destructor.
MEX_DEFINE(delete) (int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
InputArguments input(nrhs, prhs, 1);
OutputArguments output(nlhs, plhs, 0);
Session<Database>::destroy(input.get(0));
}
// Member method.
MEX_DEFINE(query) (int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
InputArguments input(nrhs, prhs, 2);
OutputArguments output(nlhs, plhs, 1);
const Database& database = Session<Database>::getConst(input.get(0));
output.set(0, database.query(input.get<string>(1)));
}
// And so on...
MEX_DISPATCH
2

Для чего это стоит, вот мой взгляд на проблему. Пожалуйста, посмотрите пример файла MEX и оболочки класса в это GitHub репо. Это решение, которое я придумал некоторое время назад, и я только что нашел этот вопрос, разрабатывая ответ на связанный вопрос. Надеюсь, это будет полезно для кого-то.

Цели дизайна

  • Управление несколькими постоянными экземплярами класса C ++
  • Маленькие последовательные целочисленные маркеры, используемые в MATLAB (не приведенные указатели)
  • Прозрачно обрабатывать управление ресурсами (то есть MATLAB никогда не отвечает за память, выделенную для классов C ++):
    1. Нет утечки памяти, если MATLAB не может выполнить действие «удалить».
    2. Автоматическое освобождение, если MEX-файл преждевременно выгружен.
  • Защита от преждевременной разгрузки модуля
  • Действительность ручек неявно проверяется без проверки магического числа
  • Нет класса-оболочки или функций, имитирующих mexFunction, только интуитивно понятный
    блок переключателей в mexFunction.

Обратите внимание, что эти цели должны быть достигнуты безотносительно к любому классу MATLAB, но это также может помочь решить проблемы управления памятью. Таким образом, полученный MEX-файл можно безопасно использовать напрямую (но не слишком элегантно).

Обзор реализации

Для вашего класса C ++, class_type, mexFunction использует статическое хранилище данных для хранения постоянного (между вызовами mexFunction) таблица целочисленных дескрипторов и интеллектуальных указателей на динамически размещенные экземпляры классов. std::map используется для этой цели, что облегчает поиск известных дескрипторов, для которых гарантированно существуют только допустимые экземпляры вашего класса:

typedef unsigned int handle_type;
std::map<handle_type, std::shared_ptr<class_type>>

std::shared_ptr заботится об освобождении, когда либо (1) элемент таблицы стирается с помощью действия «удалить», либо (2) MEX-файл выгружается.

Чтобы предотвратить выгрузку MEX-файла, пока существуют экземпляры класса MATLAB, mexLock вызывается каждый раз, когда создается новый экземпляр класса C ++, добавляя к счетчику блокировок MEX-файла. Каждый раз, когда экземпляр C ++ удаляется mexUnlock вызывается, удаляя одну блокировку из счетчика блокировок.

использование

  1. [In .cpp] Перечислите различные действия (например, «Создать», «Удалить», «Вставить» и т. Д.) В перечислении «Действия». Для каждого перечисленного действия укажите строку (например, «new», «delete», «insert» и т. Д.), Которая будет передана в качестве первого аргумента функции MEX в MATLAB.
  2. [In .cpp] Настройте обработку для каждого действия в операторе switch в теле mexFunction (например, вызвать соответствующий метод класса C ++).
  3. [In .m] (Необязательно) Создайте класс, производный от cppclass, создание простых методов для действий, необходимых вашему классу.

Требования

Современный компилятор со следующими функциями C ++ 11:

  • shared_ptr
  • auto
  • enum class
  • initializer_list (за const map инициализация)

Visual Studio 2013, недавний GCC (возможно, с -std=c++11) и Clang с 3.1.

Источник

1

Альтернативный дизайн, более чистый для случая использования здесь, состоит в том, чтобы определить одноэлементный класс с init, fcnA, fcnB, fcnC, … методами … и т. Д., С соответствующими облегченными обертками.
а затем вызвать оболочки от MEX.

например

class A {
public:
A getInstance() {
if ( !instance )
instance = new A(...);
return instance;
}

void fcnA(T1 a1, T2 a2) {
//yada yada
}

private:
static A* instance;
};
A::instance = NULL;

//begin wrappers for marshalling to class method
A* getInstance( ) {
return A::getInstance();
}

void fcnA(T1 a1, T2 a2) {
getInstance()->fcnA(a1,a2);
}

//ad nauseum
0
По вопросам рекламы [email protected]