C++ Limitation Workaround Examples
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®:
Copy the C++ header file statements into
.hpp
files.Copy the source code into
.cpp
files and build, using instructions in Build Example Compiled Library Files on Windows.Execute the MATLAB code to generate the library definition.
If required, edit the library definition file.
Execute the MATLAB code to build the interface in the interface folder.
Copy the dependent library file, if any, to the interface folder.
Execute the MATLAB code to test the functionality.
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 this
Student.hpp
header file pass std::stack
objects. If you build the MATLAB interface, functions readStudents
and
getStudents
are not included.
#ifndef STUDENT_HEADER #define STUDENT_HEADER #include <stack> #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<Student>& students); DLL_EXPORT std::stack<Student> getStudents(int size); #endif
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<Student>& students) { } DLL_EXPORT std::stack<Student> getStudents(int size) { std::stack<Student> students; for (int i = 0; i < size; i++) { students.push(Student(i+1)); } return students; }
Create the
Student.hpp
header file.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 <stack> #include <stdexcept> template<typename T> class CStack { std::stack<T> 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
Define a function
readStudentsWrapper
to call thereadStudents
function using theCStack
class andgetStudentsWrapper
to call thegetStudents
function. Include these functions in a wrapper header file namedStudentWrapper.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<Student>& students) { readStudents(students.getData()); } //wrapper function to access the function that returns the std::stack CStack<Student> getStudentsWrapper(int size) { auto students = getStudents(size); CStack<Student> cstackStudents(students); return cstackStudents; }
Generate a library definition in an interface named
stack
.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<Student>' 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<Student>' 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 functionsreadStudentsWrapper
andgetStudentsWrapper
instead ofreadStudents
andgetStudents
. The constructor to classCStack
and membergetData
are used internally and are not callable from the interface.Build the interface.
build(definestack) addpath('stack')
Copy the library file
Student.dll
to thestack
folder.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)
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 this
Templates.hpp
header file is not instantiated.
// Header for Template class #ifndef templates_Header #define templates_Header template <class T> 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
To include the
Pairs
class, create this wrapper header fileTemplatesWrapper.hpp
. Assume thatPairs
supportsint
anddouble
data types.//Wrapper to instantiate template class Pairs #include "Templates.hpp" /* Data types that will be used for Pairs class. */ template class Pairs<int>; template class Pairs<double>;
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).
Build the interface.
build(defineTemplates) addpath('Templates')
Create
Pairs
objects and call thegetVal1
andgetVal2
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 macro
PI
. 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
To run this example on Windows, create the
Area.lib
andArea.dll
files from thisArea.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 piVal*radius*radius; }
Create the
Area.hpp
header file.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; }
Generate the library definition in an interface named
Area
.clibgen.generateLibraryDefinition( ... ["Area.hpp","WrapperPI.hpp"], ... InterfaceName="Area", ... Libraries="Area.lib", ... TreatObjectPointerAsScalar=true, ... Verbose=true)
Build the interface.
build(defineArea) addpath('Area')
Copy the library file
Area.dll
to theArea
folder.Call
getArea
.pi = clib.Area.getPI; area = clib.Area.getArea(2,pi)
area = 12.5660
String Arrays
A MATLAB interface to a C++ library does not include functions with arguments
std::string
for element type of vector. For example, the
readStringVector
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 <vector> #include <string> #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::vector<std::string>& stringVector); //readStringVector function gets dropped as vector of std::string input is not supported in MATLAB C++ interface. DLL_EXPORT std::vector<std::string> getStringVector(int size); //getStringVector function gets dropped as return type of vector of std::string is not supported for MATLAB C++ Interface #endif
To run this example on Windows, create the
StringVector.lib
andStringVector.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::vector<std::string>& stringVector) { } DLL_EXPORT std::vector<std::string> getStringVector(int size) { std::vector<std::string> stringVector; for (int i = 0; i < size; i++) { stringVector.push_back(("string"+ std::to_string(i+1))); } return stringVector; }
Create the
StringVector.hpp
header file.To support
std::vector
of typestd::string
, create aCVector
class, which defines these methods to pass thestd::vector
between MATLAB and the library.Parameterized constructor:
CVector(const std::vector<T>& d): data(d)
Move constructor:
CVector(std::vector<T>&& d) : data(std::move(d))
Method to access the element at an index:
T get(int index)
Method to add elements to vectors:
void add(const T& element)
Method to get data from vectors:
const std::vector<T>& getData() const
CVector.hpp
defines this class.//Wrapper header to access/pass std::vector from MATLAB #ifndef cvector_header #define cvector_header #include <vector> template<typename T> class CVector { std::vector<T> data; public: CVector() {} CVector(const std::vector<T>& d): data(d) {} CVector(std::vector<T>&& 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<T>& getData() const { return data; } }; #endif
To include
readStringVector
andgetStringVector
, create aWrapperStringVector.hpp
header file, which defines methods to passCVector
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 <string> void wrapperReadStringVector(const CVector<std::string>& stringVec) { readStringVector(stringVec.getData()); } CVector<std::string> wrapperGetStringVector(int size) { auto strVec = getStringVector(size); CVector<std::string> cvecString(strVec); return cvecString; }
Generate the library definition in a folder named
StringVector
.clibgen.generateLibraryDefinition( ... ["StringVector.hpp","WrapperStringVector.hpp"], ... InterfaceName="StringVector", ... Libraries="StringVector.lib", ... TreatObjectPointerAsScalar=true, ... Verbose=true)
Build the interface.
build(defineWrapperStringVector) addpath('WrapperStringVector')
Copy the library file
StringVector.dll
to theStringVector
folder.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