주요 콘텐츠

Pass C++ Structures to MATLAB Functions

R2026b
Since R2026b

This example shows how to pass custom C++ structures directly to a MATLAB® function from a C++ engine application without manually converting the structure fields. In this example, you perform the following steps:

  1. Create custom structures in a C++ header file.

  2. Build a MATLAB interface to the structures.

  3. Pass the structures to a MATLAB function.

  4. Call this MATLAB function from your C++ application.

  5. Build and run the C++ application.

This example uses in-process C++ libraries through the clib interface. Passing C++ structures to MATLAB functions using out-of-process C++ libraries is not supported.

Prerequisites

Before you begin, complete these prerequisite tasks:

  • Verify that you have met all of the requirements to build a C++ program using the MATLAB Engine API for C++. For details, see Requirements to Build C++ Engine Applications.

  • Verify that you have set up a C++ development environment. For details, see Set Up C++ Development Environment.

  • Create a new work folder that is visible to the MATLAB search path. This example uses a folder named C:\cpp\work.

Define Structures in C++ Header File

Create a C++ header file that defines the structures you want to pass to MATLAB. This example defines Position and Rectangle structures in a Shapes namespace. Save the structure definitions in a file named shapes.hpp.

shapes.hpp
#include <cstdint>

namespace Shapes {

    struct Position {
        uint64_t X = 0;
        uint64_t Y = 0;
    };

    struct Rectangle {
        Position UpperLeft;
        Position LowerRight;
    };

}

Build MATLAB Interface to Structures

Build a MATLAB interface to the structures you defined. Before building the interface, select the C++ compiler you want to use by running this command:

mex -setup C++

To build the interface, use a clibgen.api.InterfaceDefinition object. (since R2026b)

For this example, the code creates a folder named ShapesLib and builds the interface, ShapesLibInterface.dll, in this folder. The Position and Rectangle structures in C++ map to clib.ShapesLib.Shapes.Position and clib.ShapesLib.Shapes.Rectangle objects in MATLAB.

icfg = clibgen.api.InterfaceConfiguration("ShapesLib",HeaderFiles="shapes.hpp",IncludePath=pwd);
idef = clibgen.api.InterfaceDefinition(icfg);
idef.build;

Before R2026b: Build the interface using the clibgen.buildInterface function.

clibgen.buildInterface("shapes.hpp",InterfaceName="ShapesLib")

Add the interface folder to the MATLAB search path so that you can use the generated clib objects in MATLAB.

addpath("C:\cpp\work\ShapesLib")

Pass Structures to MATLAB Function Using Interface

You can pass C++ structures to MATLAB functions by using the interface you built. For example, create a MATLAB function, createRectangle, that uses the ShapesLib interface to create a Rectangle structure from two input Position structures. Save the function in a file named createRectangle.m.

createRectangle.m
function rect = createRectangle(pt1,pt2)
%CREATERECTANGLE - Create rectangle using MATLAB interface to C++
    arguments (Input)
        pt1 (1,1) clib.ShapesLib.Shapes.Position
        pt2 (1,1) clib.ShapesLib.Shapes.Position
    end

    arguments (Output)
        rect (1,1) clib.ShapesLib.Shapes.Rectangle
    end

    rect = clib.ShapesLib.Shapes.Rectangle();
    rect.UpperLeft = pt1;
    rect.LowerRight = pt2;
end

The arguments blocks in this function validate the clib input and output structures. These blocks are optional but enable autocompletion for the structures in the MATLAB Editor. These type validations also enable your C++ application to internally pass the structures by reference instead of copying them field by field from MATLAB to C++.

Call MATLAB Function from C++ Application

You can call MATLAB functions that use C++ structures from your C++ application. For example, write a C++ application, myMain.cpp, that creates a rectangle using the MATLAB function and the structures defined in the header file.

  • The include statements provide access to the MATLAB Engine header file and the header file that contains the structures.

  • The USING_TYPE_WITH_MATLAB macros associate each structure with the interface library name. These macros must appear at file scope, outside of any function.

  • MATLAB starts in the same process that executes your C++ code (IN_PROCESS mode).

  • The addpath commands add the path to the folder containing your C++ code and the ShapesLib library so that they are available at run time. Update the paths shown in the application to use the paths for your platform. To avoid including these commands in your code, add the equivalent MATLAB addpath commands to your startup.m file. For more details on MATLAB startup files, see Startup Options in MATLAB Startup File.

  • The feval function calls the createRectangle MATLAB function, accepting pointers to two Position structures as input and returning a pointer to the Rectangle structure. When using feval with structures, you must specify pointers to input and output structures.

  • The application deallocates the memory referenced by the rectangle pointer before exiting. When feval returns a structure pointer, the C++ application takes ownership of the allocated memory. When you no longer need the rectangle pointer, use delete on the pointer to deallocate the memory it references.

This application runs on Windows® or Linux®. Running this application on Mac requires changes to the application logic. For more details, see the Run Application on Mac Platforms section.

myMain.cpp
#include "MatlabEngine.hpp"
#include "shapes.hpp"

USING_TYPE_WITH_MATLAB(Shapes::Position, "ShapesLib");
USING_TYPE_WITH_MATLAB(Shapes::Rectangle, "ShapesLib");

int main()
{
    using namespace matlab::engine;

    // Start in-process MATLAB
    std::unique_ptr<MATLABEngine> matlabPtr = startMATLAB(MATLABApplicationMode::IN_PROCESS);

    // Add path to working folder and MATLAB interface to C++ library
    matlabPtr->feval<void>(u"addpath", std::string("C:/cpp/work"));
    matlabPtr->feval<void>(u"addpath", std::string("C:/cpp/work/ShapesLib"));

    // Define points using Position structure
    Shapes::Position pt1, pt2;
    pt1.X = 0;
    pt1.Y = 0;
    pt2.X = 10;
    pt2.Y = 5;

    // Create Rectangle structure using feval with createRectangle.m
    Shapes::Rectangle* rectPtr = matlabPtr->feval<Shapes::Rectangle*>(
        u"createRectangle", &pt1, &pt2);

    // Display rectangle data
    std::cout << "Upper left: (" << rectPtr->UpperLeft.X
              << ", " << rectPtr->UpperLeft.Y << ")" << std::endl;
    std::cout << "Lower right: (" << rectPtr->LowerRight.X
              << ", " << rectPtr->LowerRight.Y << ")" << std::endl;

    // Deallocate Rectangle structure
    delete rectPtr;
    return 0;
}

Build and Run Application

Build and run the C++ application. Before building the application, select the C++ compiler you want to use. You must select the same compiler you used earlier to build the MATLAB interface to the structures. At the MATLAB command prompt, run this command:

mex -setup -client engine C++

Build an executable file for the application. The compiler creates the executable named myMain in the same folder as your code.

mex -client engine myMain.cpp

From the operating system command line, run the application. To run this application, your run-time environment must be configured to find MATLAB libraries, as described in Requirements to Build C++ Engine Applications.

.\myMain
Upper left: (0, 0)
Lower right: (10, 5)

The application displays the rectangle points. To modify the application, update your myMain.cpp file, and then rebuild the executable and rerun it.

Application Variations

You can customize the application to return a different number of outputs, call the MATLAB function asynchronously, or run on Mac platforms.

Return No Outputs or Multiple Outputs

In this example, the C++ application used feval to return a single output from the MATLAB function. The syntax to return no outputs or multiple outputs is slightly different.

  • If your MATLAB function returns no outputs, use void as the return value. For example, this code calls a MATLAB function, updatePosition, that modifies the Position structures of the rectangle in place, without returning a value.

    matlabPtr->feval<void>(u"updatePosition", &pt1, &pt2);

  • If your MATLAB function returns multiple outputs, use std::tuple as the return value. For example, this code calls a MATLAB function, getRectangleInfo, that returns the area of a rectangle as a double value and the center of the rectangle as a Position structure.

    auto [area, center] = matlabPtr->feval<std::tuple<double, Shapes::Position*>>(
        u"getRectangleInfo", &pt1, &pt2);

Call MATLAB Function Asynchronously

To call the MATLAB function asynchronously, use fevalAsync instead of feval. The fevalAsync function returns a FutureResult object that you can use to retrieve the output structure when the call completes. For example, this code calls createRectangle asynchronously and retrieves the result using future.get().

FutureResult<Shapes::Rectangle*> future = matlabPtr->fevalAsync<Shapes::Rectangle*>(u"createRectangle", &pt1, &pt2);
    // Do other work while MATLAB executes
Shapes::Rectangle* rectPtr = future.get();

Run Application on Mac Platforms

On Mac platforms, in-process mode requires MATLAB to run on the main thread of the process. To start MATLAB on the main thread, use matlab::engine::runMacLoopInProcess. Place your application code in a separate function and pass it to runMacLoopInProcess so that the code runs in a secondary thread.

int appCode(int argc, char *argv[]) {
    using namespace matlab::engine;
    std::unique_ptr<MATLABEngine> matlabPtr = startMATLAB(MATLABApplicationMode::IN_PROCESS);
    // Application code here
    return 0;
}

int main(int argc, char *argv[]) {
    return matlab::engine::runMacLoopInProcess(appCode, argc, argv);
}

See Also

Topics