Main Content

C++ MEX 関数の構造

MEX 関数の設計

C++ MEX 関数は、関数呼び出し演算子 operator() をオーバーライドして関数オブジェクト (ファンクター) を作成するクラスです。これらのオブジェクトは、入力を受け入れ、出力を返すことができる MATLAB® 関数のように動作します。

ヘッダー ファイル

次のヘッダー ファイルをインクルードします。

  • mex.hpp — C++ MEX API の場合、このファイルをインクルードします。

  • mexAdapter.hppMexFunction クラスを実装するために、このファイルを 1 回だけインクルードします。

名前空間

C++ MEX API はこれらの名前空間に含まれています。

  • matlab::mex — MEX インターフェイス

  • matlab::data — MATLAB データ API

  • matlab::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 関数から外部リソースを管理を参照してください。

参考

|

関連するトピック