Main Content

Operate on C++ Arrays Using Visitor Pattern

The C++ MATLAB® Data API supports the use of visitor classes via the matlab::data::apply_visitor and matlab::data::apply_visitor_ref functions. These functions accept an array or array reference and a visitor class as inputs.

The apply_visitor and apply_visitor_ref functions dispatch to the operations defined by the visitor class based on input array type. The visitor class defines operations to perform on specific types of array.

Use the visitor pattern in cases such as these:

  • There are many operations that you need to perform on an array and the way to perform them depends on the type of the array.

  • The array returned by a function can be of different known types and you want to handle all cases.

  • You are working with heterogeneous structures like cell arrays or structure arrays.

Dispatch on Array or Array Reference

The apply_visitor function dispatches to the visitor class operation based on the type of the input array. The syntax for calling apply_visitor accepts a matlab::data::Array and your visitor class instance:

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

The apply_visitor_ref function dispatches to the visitor class operation based on the type of the array reference passed as an input. The syntax for calling apply_visitor_ref accepts a matlab::data::ArrayRef and your visitor class instance:

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

Overloading operator()

Implement your visitor class to overload the operator operator() for the array types you want to operate on. For example, suppose one operation that you want to implement is to return the text contained in a matlab::data::CharArray as a std::string. Implement the operation like this:

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

As another example, suppose that you want to negate the logical values in a matlab::data::TypedArray. In this case, use a reference to the array:

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

You must use an element reference in the range-based for loop to change the value in the array. Only use matlab::data::TypedArrayRef on elements of a container type such as a struct or cell.

Visitor Class to Display Contents of Cell Array

This example shows how to use a visitor class to define operations to perform on specific types of matlab::data::Array.

The DisplayVisitor class implements operations to display the contents of cell arrays for arrays of types bool, double, and char, and contained cell arrays. You can add new operations to support other cell array contents by adding more overloaded functions.

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);
        }
    }

To use the class, pass a cell array to the DisplayCell function.

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;
}

Visitor Class to Modify Contents of Cell Array

In this example, the CellModifyVisitor class implements the operations to modify the contents of cell arrays of types bool, double, and char, and contained cell arrays. You can add new operations to support other cell array contents by adding more overloaded functions.

The ModifyCell function calls apply_visitor_ref in a loop for each element in the cell array. Because the objective is to modify the contents of the cell array, this example uses references to the cell array contents.

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);
    }
}

To use the class, pass a cell array to the ModifyCell function.

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;
}

See Also

|

Related Topics