Main Content

ビジター パターンを使用した C++ 配列上での演算

C++ MATLAB® データ API は、関数 matlab::data::apply_visitor および matlab::data::apply_visitor_ref を介したビジター クラスの使用をサポートします。これらの関数は配列または配列参照およびビジター クラスを入力として受け入れます。

関数 apply_visitor および apply_visitor_ref は、入力配列型に基づいてビジター クラスで定義された演算にディスパッチします。ビジター クラスは特定の配列型で実行する演算を定義します。

以下のような場合にビジター パターンを使用します。

  • 配列上で多数の演算を実行する必要があり、実行方法が配列の型によって異なる。

  • 関数から返される配列は異なる既知の型になる可能性があるが、すべてのケースを処理する必要がある。

  • cell 配列や構造体配列のような異種混合の構造体で作業をしている。

配列または配列参照へのディスパッチ

関数 apply_visitor は入力配列の型に基づいてビジター クラスの演算にディスパッチします。apply_visitor を呼び出す構文は matlab::data::Array とビジター クラス インスタンスを受け入れます。

auto apply_visitor(matlab::data::Array a, V visitor)

関数 apply_visitor_ref は、入力として渡された配列参照の型に基づいてビジター クラスの演算にディスパッチします。apply_visitor_ref を呼び出す構文は matlab::data::ArrayRef とビジター クラス インスタンスを受け入れます。

auto apply_visitor_ref(const matlab::data::ArrayRef& a, V visitor)

operator() のオーバーロード

演算を行う配列型の演算子 operator() をオーバーロードするには、ビジター クラスを実装します。たとえば、実装する演算の 1 つが、matlab::data::CharArraystd::string として含まれているテキストを返すとします。以下のように演算を実装します。

std::string operator()(matlab::data::CharArray arr){
   return arr.toAscii();
}

別の例として、matlab::data::TypedArray の論理値を否定するとします。この場合、配列への参照を使用します。

void operator()(TypedArrayRef<bool> boolArrRef) {
    std::cout << "Negate logical value: " << std::endl;
    for (auto &b : boolArrRef) {
        b = !b;
    }       
}

配列の値を変更するには、範囲に基づく for ループで要素参照を使用しなければなりません。

cell 配列の内容を表示するビジター クラス

この例では、ビジター クラスを使用して matlab::data::Array の特定の型に対して実行する演算を定義する方法を示します。

DisplayVisitor クラスは、配列型が booldoublechar の cell 配列の内容、およびそこに含まれている cell 配列を表示するための演算を実装します。オーバーロードされた関数をさらに追加して、他の cell 配列の内容をサポートする新しい演算を追加できます。

type DisplayVisitor.cpp
#include "MatlabDataArray.hpp"
#include <iostream>

using namespace matlab::data;
void DisplayCell(const CellArray cellArray);

    class DisplayVisitor {
    public:
        template <typename U>
        void operator()(U arr) {}

        void operator()(const TypedArray<bool> boolArr) {
            std::cout << "Cell contains logical array: " << std::endl;
            for (auto b : boolArr) {
                printf_s("%d ", b);
            }
            std::cout << "\n";
        }

        void operator()(const TypedArray<double> doubleArr) {
            std::cout << "Cell contains double array: " << std::endl;
            for (auto elem : doubleArr) {
                std::cout << elem << " ";
            }
            std::cout << "\n";
        }

        void operator()(const CharArray charArr) {
            std::cout << "Cell contains char array: " << std::endl;
            for (auto elem : charArr) {
                std::cout << char(elem);
            }
            std::cout << "\n";
        }

        void operator()(const CellArray containedCellArray) {
            DisplayCell(containedCellArray);
        }
    };

    void DisplayCell(const CellArray cellArray) {
        DisplayVisitor v;
        for (auto elem : cellArray) {
            apply_visitor(elem, v);
        }
    }

クラスを使用するには、cell 配列を関数 DisplayCell に渡します。

type callDisplayCell.cpp
int main() {
    ArrayFactory factory;

    // Create cell array
    matlab::data::CellArray cellArray = factory.createCellArray({ 1,4 },
        factory.createCharArray("A char array"),
        factory.createArray<bool>({ 1,2 }, { false, true }),
        factory.createArray<double>({ 2,2 }, { 1.2, 2.2, 3.2, 4.2 }),
        factory.createCellArray({ 1,1 }, false));

    // Call function 
    DisplayCell(cellArray);

    return 0;
}

cell 配列の内容を変更するビジター クラス

この例では、CellModifyVisitor クラスは、型が booldoublechar の cell 配列の内容、およびそこに含まれている cell 配列を変更するための演算を実装します。オーバーロードされた関数をさらに追加して、他の cell 配列の内容をサポートする新しい演算を追加できます。

関数 ModifyCell は、ループ内で cell 配列の各要素に対して apply_visitor_ref を呼び出します。ここでは cell 配列の内容を変更することが目的であるため、この例では cell 配列の内容への参照を使用します。

type CellModifyVisitor.cpp
#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include <iostream>

using namespace matlab::data;
void ModifyCell(CellArray &cellArray);

class CellModifyVisitor {
public:
    template <typename U>
    void operator()(U arr) {}

    void operator()(TypedArrayRef<bool> boolArrRef) {
        std::cout << "Negate logical value: " << std::endl;
        for (auto &b : boolArrRef) {
            b = !b;
        }       
    }

    void operator()(TypedArrayRef<double> doubleArrRef) {
        std::cout << "Add 1 to each value: " << std::endl;
        for (auto &elem : doubleArrRef) {
            elem = elem + 1;
        }
        std::cout << "\n";
    }

    void operator()(CharArrayRef charArrRef) {
        std::cout << "Modify char array" << std::endl;
        ArrayFactory factory;
        charArrRef = factory.createCharArray("Modified char array");
    }
 
    void operator()(CellArrayRef containedCellArray) {
        CellModifyVisitor v;
        for (auto elem : containedCellArray) {
            apply_visitor_ref(elem, v);
        }
    }
    
};

void ModifyCell(CellArray &cellArray) {
    CellModifyVisitor v;
    for (auto elem : cellArray) {
        apply_visitor_ref(elem, v);
    }
}

クラスを使用するには、cell 配列を関数 ModifyCell に渡します。

type callModifyCell.cpp
int main() {
    ArrayFactory factory;

    // Create cell array
    matlab::data::CellArray cellArray = factory.createCellArray({ 1,4 },
        factory.createCharArray("A char array"),
        factory.createArray<bool>({ 1,2 }, { false, true }),
        factory.createArray<double>({ 2,2 }, { 1.2, 2.2, 3.2, 4.2 }),
        factory.createCellArray({ 1,1 }, false));

    // Call function
    ModifyCell(cellArray);

    return 0;
}

参考

|

関連するトピック