У меня есть набор 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
и вызвать функцию внутренне, используя это и переданные данные.
AFAIK, нет простого способа сделать это, потому что mexFunction
интерфейс скорее плоский. Тем не менее, я думаю, что есть несколько способов, которые помогут вам приблизиться. Выберите лучший в зависимости от ваших потребностей.
Самый простой — создать глобальный экземпляр dlp
класс в вашей функции mex. Заставьте первый параметр функции mex вызвать строку, которая указывает, какую функцию-член глобального объекта следует вызывать. Очевидным недостатком является то, что вы превратили свою функцию mex в синглтон.
Если вам нужно больше, чем один dlp
Например, вы можете создать глобальный контейнер в функции mex, std::map<std::string, dlp>
например, а затем обратиться к каждому dlp
экземпляр по какому-то имени из MATLAB. Например, чтобы создать новый экземпляр, вы должны вызвать функцию mex с именем, которое еще не существует в map
, Затем вы можете вызвать mex-функцию с этим именем, строкой, указывающей, какую функцию-член вызывать, и любыми параметрами, передаваемыми в функцию-член. Также установите некоторые соглашения, по которым вы можете стереть dlp
экземпляр из map
,
Аналогично второму решению, вместо именования dlp
случаи, когда вы могли бы вернуться ручки каждому экземпляру. Например, создать глобальный std::set<dlp *>
и когда у вас есть функция mex, создайте новый dlp
Например, добавьте его в set
и вернуть копию указателя на выделенный объект в MATLAB (вставьте его в скалярную переменную типа mxUINT64_CLASS
). Последующие вызовы для вызова функций-членов этого объекта справиться переменная в функцию mex из MATLAB, вы соответствующим образом преобразуете ее в файл mex, находите ее в set
и вызывать функции-члены.
Ни один из этих методов не особенно хорош, но это единственный известный мне способ вызова функций-членов класса C ++ из файла mex.
Возможно, вы захотите взглянуть на это представление в MATLAB Central. Насколько я знаю, это демонстрирует наилучшую практику, разработанную по совету группы новостей от многих, включая MathWorkers.
Проще всего спроектировать оболочку 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
Для чего это стоит, вот мой взгляд на проблему. Пожалуйста, посмотрите пример файла MEX и оболочки класса в это GitHub репо. Это решение, которое я придумал некоторое время назад, и я только что нашел этот вопрос, разрабатывая ответ на связанный вопрос. Надеюсь, это будет полезно для кого-то.
Цели дизайна
Обратите внимание, что эти цели должны быть достигнуты безотносительно к любому классу 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
вызывается, удаляя одну блокировку из счетчика блокировок.
использование
mexFunction
(например, вызвать соответствующий метод класса C ++).Требования
Современный компилятор со следующими функциями C ++ 11:
shared_ptr
auto
enum class
initializer_list
(за const map
инициализация)Visual Studio 2013, недавний GCC (возможно, с -std=c++11
) и Clang с 3.1.
mexFunction
и карта экземпляра). Переименуйте и отредактируйте это для C ++, которым вы хотите управлять.Альтернативный дизайн, более чистый для случая использования здесь, состоит в том, чтобы определить одноэлементный класс с 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