C++ Limitation Workaround Examples - MATLAB & Simulink (original) (raw)

Main Content

If your compiled library contains data types or language features not supported by the MATLAB® interface to C++ libraries, you might be able to include this functionality by creating a wrapper header file. This topic and the C++ Interface workarounds for limitations article provide examples for some limitations. For more information, see Limitations to C/C++ Support.

To run the workaround examples on Windows®:

Class Objects in std Namespace

A MATLAB interface to a C++ library does not include functions that use objects defined in the std namespace. For example, the functions in thisStudent.hpp header file pass std::stack objects. If you build the MATLAB interface, functions readStudents andgetStudents are not included.

#ifndef STUDENT_HEADER #define STUDENT_HEADER

#include

#ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT attribute((visibility ("default"))) #endif

class DLL_EXPORT Student { int rollNumber; public: Student(); Student(int rollNo); int getRollNumber(); };

DLL_EXPORT void readStudents(const std::stack& students);

DLL_EXPORT std::stack getStudents(int size);

#endif

  1. To run this example on Windows, create the Student.lib andStudent.dll files from thisStudent.cpp source file, using Build Example Compiled Library Files on Windows.

#define EXPORT
#include "Student.hpp"
Student::Student() : rollNumber(0) {}
Student::Student(int rollNo) : rollNumber(rollNo) {}
int Student::getRollNumber() {
return rollNumber;
}
DLL_EXPORT void readStudents(const std::stack& students) {
}
DLL_EXPORT std::stack getStudents(int size) {
std::stack students;
for (int i = 0; i < size; i++) {
students.push(Student(i+1));
}
return students;
} 2. Create the Student.hpp header file. 3. Create a class CStack to represent anstd::stack object. Put this definition in a header fileCStack.hpp.
//Wrapper header to access/pass std::stack objects from MATLAB
#ifndef stack_header
#define stack_header
#include
#include
template
class CStack {
std::stack data;
public:
CStack() {}

// This parameterized constructor is required for the wrapper functions  
// and is not included in the MATLAB interface  
CStack(const std::stack<T>& d):data(d) {}  
// Function to access the topmost element in stack  
T* get() {  
    if (data.empty())  
        throw std::runtime_error("Retrieving element from Empty Stack");  
    return &data.top();  
}  
  
// Function to remove elements from stack  
void remove() {  
    if (data.empty())  
        throw std::runtime_error("Stack is empty");  
    data.pop();  
}  
  
// Function to add elements to stack  
void add(const T* element) {  
    data.push(*element);  
}  
  
// This method is required for the wrapper functions, and  
// is not included in the MATLAB interface  
const std::stack<T>& getData() const{  
    return data;  
}  

};
#endif 4. Define a function readStudentsWrapper to call thereadStudents function using the CStack class and getStudentsWrapper to call thegetStudents function. Include these functions in a wrapper header file named StudentWrapper.hpp.
//Header to call readStudents and getStudents functions from MATLAB
#include "Student.hpp"
#include "CStack.hpp"
//wrapper function to access the function that accepts std::stack input
void readStudentsWrapper(const CStack& students) {
readStudents(students.getData());
}
//wrapper function to access the function that returns the std::stack
CStack getStudentsWrapper(int size) {
auto students = getStudents(size);
CStack cstackStudents(students);
return cstackStudents;
} 5. Generate a library definition in an interface namedstack.
clibgen.generateLibraryDefinition( ...
["Student.hpp","StudentWrapper.hpp"], ...
InterfaceName="stack", ...
Libraries="Student.lib", ...
TreatObjectPointerAsScalar=true, ...
Verbose=true);
Warning: File 'manifest.json' not found.
Warning: Some C++ language constructs in the header file are not supported and not imported.
Did not add 'readStudents' at Student.hpp:24.
  Type 'stack' is from std namespace or system header and is not supported.
Did not add 'getStudents' at Student.hpp:26.
  Type 'stack' is from std namespace or system header and is not supported.
Did not add constructor to class 'CStack' at CStack.hpp:16.
  Type 'stack' is from std namespace or system header and is not supported.
Did not add member 'getData' to class 'CStack' at CStack.hpp:39.
  Type 'stack' is from std namespace or system header and is not supported.

Using MinGW64 Compiler (C++) compiler.
Generated definition file definestack.m and data file 'stackData.xml'
contain definitions for 13 constructs supported by MATLAB.
Build using build(definestack).
Ignore the Did not add messages. In MATLAB, you call functions readStudentsWrapper andgetStudentsWrapper instead ofreadStudents and getStudents. The constructor to class CStack and membergetData are used internally and are not callable from the interface. 6. Build the interface.
build(definestack)
addpath('stack') 7. Copy the library file Student.dll to thestack folder. 8. Call readStudentsWrapper.
studentsStack = clib.stack.CStack_Student_;
studentsStack.add(clib.stack.Student(1))
studentsStack.add(clib.stack.Student(2))
studentsStack.add(clib.stack.Student(3))
clib.stack.readStudentsWrapper(studentsStack) 9. Call getStudentsWrapper.
clear studentsStack;
studentsStack = clib.stack.getStudentsWrapper(3);
student = studentsStack.get; % returns topmost element from studentStack
studentsStack.remove % removes topmost element of stack

Class Templates With Incomplete or Missing Instantiations

A MATLAB interface to a C++ library does not support uninstantiated template classes. For example, the class Pairs in thisTemplates.hpp header file is not instantiated.

// Header for Template class #ifndef templates_Header #define templates_Header

template class Pairs { public: T val1; T val2; Pairs() : val1(0), val2(0) {} Pairs(T first, T second) : val1(first), val2(second) {} T getVal1() { return val1; } T getVal2() { return val2; } }; #endif

  1. To include the Pairs class, create this wrapper header fileTemplatesWrapper.hpp. Assume thatPairs supports int anddouble data types.
    //Wrapper to instantiate template class Pairs

#include "Templates.hpp"
/* Data types that will be used for Pairs class. */
template class Pairs;
template class Pairs; 2. Generate the library definition.
clibgen.generateL ibraryDefinition( ...
["TemplatesWrapper.hpp","Templates.hpp"], ...
InterfaceName="Templates", ...
Verbose=true)
Generated definition file defineTemplates.m and data file 'TemplatesData.xml'
contain definitions for 16 constructs supported by MATLAB.
Build using build(defineTemplates). 3. Build the interface.
build(defineTemplates)
addpath('Templates') 4. Create Pairs objects and call thegetVal1 and getVal2 functions.
Pairs1 = clib.Templates.Pairs_int_(2,3);
Val1 = Pairs1.getVal1;
Pairs2 = clib.Templates.Pairs_double_(4.5,10.9);
Val2 = Pairs2.getVal2;
Pairs3 = clib.Templates.Pairs_int_(4.3,10.9);
Val2 = Pairs3.getVal2;

Preprocessor Directives

A MATLAB interface to a C++ library does not support preprocessor directives (macros). For example, this Area.hpp header file defines the macroPI. If you build a MATLAB interface, PI is not included.

//Header with Macro preprocessor directive #ifndef area_header #define area_header

#ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT attribute((visibility ("default"))) #endif

#define PI 3.1415

DLL_EXPORT double getArea(int radius, double piVal);

#endif

  1. To run this example on Windows, create the Area.lib andArea.dll files from this Area.cpp source file, using Build Example Compiled Library Files on Windows.

#define EXPORT
#include "Area.hpp"
DLL_EXPORT double getArea(int radius, double piVal) {
return piValradiusradius;
} 2. Create the Area.hpp header file. 3. To include PI, create this wrapper header fileWrapperPI.hpp which defines functiongetPI to get the value of the preprocessor directive.
//Wrapper to access the preprocessor directive value
#include "Area.hpp"
double getPI(){ //Wrapper function retrieves the value of PI
return PI;
} 4. Generate the library definition in an interface namedArea.
clibgen.generateLibraryDefinition( ...
["Area.hpp","WrapperPI.hpp"], ...
InterfaceName="Area", ...
Libraries="Area.lib", ...
TreatObjectPointerAsScalar=true, ...
Verbose=true) 5. Build the interface.
build(defineArea)
addpath('Area') 6. Copy the library file Area.dll to theArea folder. 7. Call getArea.
pi = clib.Area.getPI;
area = clib.Area.getArea(2,pi)

String Arrays

A MATLAB interface to a C++ library does not include functions with argumentsstd::string for element type of vector. For example, thereadStringVector and getStringVector functions in this StringVector.hpp header file are not included when you build a MATLAB interface.

//Header file which accepts and return the vector of std::string #ifndef stringVec_header #define stringVec_header #include #include

#ifdef _WIN32 #ifdef EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #else #define DLL_EXPORT attribute((visibility ("default"))) #endif

DLL_EXPORT void readStringVector(const std::vectorstd::string& stringVector); //readStringVector function gets dropped as vector of std::string input is not supported in MATLAB C++ interface.

DLL_EXPORT std::vectorstd::string getStringVector(int size); //getStringVector function gets dropped as return type of vector of std::string is not supported for MATLAB C++ Interface

#endif

  1. To run this example on Windows, create the StringVector.lib and StringVector.dll files from thisStringVector.cpp source file, using Build Example Compiled Library Files on Windows.

#define EXPORT
#include "StringVector.hpp"
DLL_EXPORT void readStringVector(const std::vectorstd::string& stringVector) {
}
DLL_EXPORT std::vectorstd::string getStringVector(int size) {
std::vectorstd::string stringVector;
for (int i = 0; i < size; i++) {
stringVector.push_back(("string"+ std::to_string(i+1)));
}
return stringVector;
} 2. Create the StringVector.hpp header file. 3. To support std::vector of typestd::string, create a CVector class, which defines these methods to pass the std::vector between MATLAB and the library.

#ifndef cvector_header
#define cvector_header
#include
template
class CVector {
std::vector data;
public:
CVector() {}
CVector(const std::vector& d): data(d) {}
CVector(std::vector&& d) : data(std::move(d)) {}
T get(int index) {
return data.at(index-1);
}
void add(const T& element) {
data.push_back(element);
}
const std::vector& getData() const {
return data;
}
};
#endif 4. To include readStringVector andgetStringVector, create aWrapperStringVector.hpp header file, which defines methods to pass CVector arguments to the C++ library methods.
// Header that allows the readStringVector and getStringVector functions
// to be accessed from MATLAB interface
#include "StringVector.hpp"
#include "CVector.hpp"
#include
void wrapperReadStringVector(const CVectorstd::string& stringVec) {
readStringVector(stringVec.getData());
}
CVectorstd::string wrapperGetStringVector(int size) {
auto strVec = getStringVector(size);
CVectorstd::string cvecString(strVec);
return cvecString;
} 5. Generate the library definition in a folder namedStringVector.
clibgen.generateLibraryDefinition( ...
["StringVector.hpp","WrapperStringVector.hpp"], ...
InterfaceName="StringVector", ...
Libraries="StringVector.lib", ...
TreatObjectPointerAsScalar=true, ...
Verbose=true) 6. Build the interface.
build(defineWrapperStringVector)
addpath('WrapperStringVector') 7. Copy the library file StringVector.dll to theStringVector folder. 8. Call the functions.
% Instantiate the CVector class
stringVectorObj = clib.StringVector.CVector_std____cxx11__basic_string_char_Std__char_traits_c;
% Add elements to vector
stringVectorObj.add("Jack");
stringVectorObj.add("John");
stringVectorObj.add("Joe");
% Call function with std::string vector input with CVector
clib.StringVector.wrapperReadStringVector(stringVectorObj);
clear stringVectorObj;

Build Example Compiled Library Files on Windows

At the Windows command prompt, add the path to the MinGW-w64 compiler to the system path. For example, if the compiler is at mingwpathname, then type:

set mingwpath = 'mingwpathname'; set PATH=%mingwpath%;%PATH%

Navigate to the location of C++ source files.

Run these commands to generate the library file from the source file_`source`_.cpp:

g++ -c source.cpp -o source.obj -std=c++11 g++ -shared -o source.dll source.obj -Wl,--out-implib,source.lib

See Also

Topics