C++ MEX 関数の構造
MEX 関数の設計
C++ MEX 関数は、関数呼び出し演算子 operator()
をオーバーライドして関数オブジェクト (ファンクター) を作成するクラスです。これらのオブジェクトは、入力を受け入れ、出力を返すことができる MATLAB® 関数のように動作します。
ヘッダー ファイル
次のヘッダー ファイルをインクルードします。
mex.hpp
— C++ MEX API の場合、このファイルをインクルードします。mexAdapter.hpp
—MexFunction
クラスを実装するために、このファイルを 1 回だけインクルードします。
名前空間
C++ MEX API はこれらの名前空間に含まれています。
matlab::mex
— MEX インターフェイスmatlab::data
— MATLAB データ APImatlab::engine
— C++ 用のエンジン API
エントリ ポイント
C++ MEX 関数を、matlab::mex::Function
クラスから派生する MexFunction
という名前のクラスとして定義します。MexFunction
クラスは matlab::mex::Function
クラスのバーチャル operator()
をオーバーライドします。
#include "mex.hpp"
#include "mexAdapter.hpp"
class MexFunction : public matlab::mex::Function {
public:
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
// check input arguments
// implement function
...
}
}
引数の受け渡し
MATLAB は各入力引数を、matlab::mex::ArgumentList
コンテナー内の matlab::data::Array
として渡します。ArgumentList
配列にインデックス付けして、各入力にアクセスします。たとえば、inputs[0]
は最初の入力、inputs[1]
は 2 番目の入力、以下同様に続きます。変数 inputs
の要素数は、MEX 関数が呼び出されたときにその関数に渡される入力引数の値に等しくなります。ArgumentList
は反復子をサポートし、範囲ベースの for
ループで使用できます。
出力引数を出力変数に代入します。たとえば、outputs[0]
は代入された最初の引数、outputs[1]
は 2 番目の引数、以下同様に続きます。変数 outputs
の要素数は、関数が呼び出されたときに代入される出力の数に等しくなります。
入力引数を、他の型の MATLAB データ配列に代入すると便利な場合がよくあります。matlab::data::TypedArray<T>
や matlab::data::CharArray
などの特定の型は、反復子や変換関数などの追加機能を提供します。入力の型と一致する型を選択してください。
たとえば、次の MEX 関数は、入力配列を matlab::data::TypedArray<double>
に代入します。この配列タイプは、範囲ベースの for ループをサポートします。これを使用して、配列の各要素を 2 で乗算します。変更した配列は変数 outputs
に返されます。
#include "mex.hpp"
#include "mexAdapter.hpp"
using namespace matlab::data;
using matlab::mex::ArgumentList;
class MexFunction : public matlab::mex::Function {
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
// Validate arguments
checkArguments(outputs, inputs);
// Implement function
TypedArray<double> doubleArray = std::move(inputs[0]);
for (auto& elem : doubleArray) {
elem *= 2;
}
// Assign outputs
outputs[0] = doubleArray;
}
void checkArguments(ArgumentList outputs, ArgumentList inputs) {
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
ArrayFactory factory;
if (inputs[0].getType() != ArrayType::DOUBLE ||
inputs[0].getType() == ArrayType::COMPLEX_DOUBLE)
{
matlabPtr->feval(u"error", 0,
std::vector<Array>({ factory.createScalar("Input must be double array") }));
}
if (outputs.size() > 1) {
matlabPtr->feval(u"error", 0,
std::vector<Array>({ factory.createScalar("Only one output is returned") }));
}
}
};
MEX 関数をビルドして実行します。
mex timesTwo.cpp
timesTwo(1:10)
ans = 2 4 6 8 10 12 14 16 18 20
引数の検証の詳細については、入力と出力の処理を参照してください。
クラスのコンストラクターとデストラクター
MATLAB から MEX 関数を呼び出すと、MexFunction
クラスがインスタンス化されます。たとえば、この MATLAB ステートメントは myMEXFunction.cpp
ファイルによって定義される MexFunction
クラスのインスタンスを作成します。
output = myMEXFunction(input);
このインスタンスは、MATLAB clear
mex
コマンドを呼び出すまで存続します。
クラスのコンストラクターとデストラクターを実装すると、MexFunction
オブジェクトの構成時に特定のタスクを実行できます。たとえば、次のコード スニペットは、コンストラクターでテキスト ファイルを読み取り用に開き、デストラクターでファイルを閉じます。
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <fstream>
using matlab::mex::ArgumentList;
class MexFunction : public matlab::mex::Function {
std::ifstream inFile;
public:
MexFunction() {
inFile.open("someTextFile.txt");
}
~MexFunction() {
inFile.close();
}
void operator()(ArgumentList outputs, ArgumentList inputs) {
....
}
};
例については、MEX 関数から外部リソースを管理を参照してください。
参考
matlab::data::Array
| matlab::data::TypedArray