C++ の制限を回避する例
使用しているコンパイル済みライブラリに、C++ ライブラリに対する MATLAB® インターフェイスでサポートされていないデータ型または言語機能が含まれている場合、ラッパー ヘッダー ファイルを作成することにより、この機能を含めることができる場合があります。このトピックと、制限に関する C++ インターフェイス回避方法の記事では、一部の制限に関する例を提供します。詳細については、C/C++ サポートに関する制限を参照してください。
Windows® で回避方法の例を実行するには、次を行います。
C++ ヘッダー ファイルのステートメントを
.hppファイルにコピーします。ソース コードを
.cppファイルにコピーし、Windows でのコンパイル済みライブラリ ファイルのビルド例の手順を使用してビルドします。MATLAB コードを実行して、ライブラリ定義を生成します。
必要に応じて、ライブラリ定義ファイルを編集します。
MATLAB コードを実行して、インターフェイス フォルダー内にインターフェイスをビルドします。
依存ライブラリ ファイルがある場合はインターフェイス フォルダーにコピーします。
MATLAB コードを実行して、機能をテストします。
std 名前空間のクラス オブジェクト
C++ ライブラリに対する MATLAB インターフェイスには、std 名前空間で定義されたオブジェクトを使用する関数が含まれていません。たとえば、次のヘッダー ファイル Student.hpp 内の関数は、std::stack オブジェクトを渡します。MATLAB インターフェイスをビルドする場合、関数 readStudents および getStudents は含まれません。
#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この例を Windows で実行するには、Windows でのコンパイル済みライブラリ ファイルのビルド例を使用して、ソース ファイル
Student.cppからファイルStudent.libおよびStudent.dllを作成します。#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; }Student.hppヘッダー ファイルを作成します。std::stackオブジェクトを表すクラスCStackを作成します。この定義をヘッダー ファイルCStack.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; } }; #endifCStackクラスを使用して関数readStudentsを呼び出す関数readStudentsWrapperと、関数getStudentsを呼び出す関数getStudentsWrapperを定義します。これらの関数を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<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; }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).
Did not addのメッセージを無視します。MATLAB で、readStudentsとgetStudentsの代わりに関数readStudentsWrapperとgetStudentsWrapperを呼び出します。クラスCStackのコンストラクターとメンバーgetDataは内部で使用され、インターフェイスから呼び出すことはできません。インターフェイスをビルドします。
build(definestack) addpath('stack')ライブラリ ファイル
Student.dllをstackフォルダーにコピーします。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)
getStudentsWrapperを呼び出します。clear studentsStack; studentsStack = clib.stack.getStudentsWrapper(3); student = studentsStack.get; % returns topmost element from studentStack studentsStack.remove % removes topmost element of stack
インスタンス化が不完全か不足しているクラス テンプレート
C++ ライブラリに対する MATLAB インターフェイスは、インスタンス化されていないテンプレート クラスをサポートしていません。たとえば、次のヘッダー ファイル Templates.hpp 内の Pairs クラスはインスタンス化されていません。
// 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;
}
};
#endifPairsクラスを含めるには、次のラッパー ヘッダー ファイルTemplatesWrapper.hppを作成します。Pairsはintおよびdoubleのデータ型をサポートすると仮定します。//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>;
ライブラリ定義を生成します。
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(defineTemplates) addpath('Templates')Pairsオブジェクトを作成し、関数getVal1およびgetVal2を呼び出します。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;
プリプロセッサ命令
C++ ライブラリに対する MATLAB インターフェイスは、プリプロセッサ命令 (マクロ) をサポートしていません。たとえば、次のヘッダー ファイル Area.hpp は、マクロ PI を定義します。MATLAB インターフェイスをビルドする場合、PI は含められません。
//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この例を Windows で実行するには、Windows でのコンパイル済みライブラリ ファイルのビルド例を使用して、ソース ファイル
Area.cppからファイルArea.libおよびArea.dllを作成します。#define EXPORT #include "Area.hpp" DLL_EXPORT double getArea(int radius, double piVal) { return piVal*radius*radius; }Area.hppヘッダー ファイルを作成します。PIを含めるには、プリプロセッサ命令の値を取得する関数getPIを定義する次のラッパー ヘッダー ファイルWrapperPI.hppを作成します。//Wrapper to access the preprocessor directive value #include "Area.hpp" double getPI(){ //Wrapper function retrieves the value of PI return PI; }Areaという名前のインターフェイス内にライブラリ定義を生成します。clibgen.generateLibraryDefinition( ... ["Area.hpp","WrapperPI.hpp"], ... InterfaceName="Area", ... Libraries="Area.lib", ... TreatObjectPointerAsScalar=true, ... Verbose=true)
インターフェイスをビルドします。
build(defineArea) addpath('Area')ライブラリ ファイル
Area.dllをAreaフォルダーにコピーします。getAreaを呼び出します。pi = clib.Area.getPI; area = clib.Area.getArea(2,pi)
area = 12.5660
string 配列
C++ ライブラリに対する MATLAB インターフェイスは、ベクトルの要素型について引数 std::string をもつ関数を含みません。たとえば、次のヘッダー ファイル StringVector.hpp 内の関数 readStringVector と getStringVector は、MATLAB インターフェイスのビルド時に含められません。
//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この例を Windows で実行するには、Windows でのコンパイル済みライブラリ ファイルのビルド例を使用して、ソース ファイル
StringVector.cppからファイルStringVector.libおよびStringVector.dllを作成します。#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; }StringVector.hppヘッダー ファイルを作成します。std::string型のstd::vectorをサポートするには、MATLAB とライブラリとの間でstd::vectorを受け渡す次のメソッドを定義するCVectorクラスを作成します。パラメーター化されたコンストラクター:
CVector(const std::vector<T>& d): data(d)
移動コンストラクター:
CVector(std::vector<T>&& d) : data(std::move(d))
インデックス位置の要素にアクセスするメソッド:
T get(int index)
ベクトルに要素を追加するメソッド:
void add(const T& element)
ベクトルからデータを取得するメソッド:
const std::vector<T>& getData() const
CVector.hppは次のクラスを定義します。//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; } }; #endifreadStringVectorとgetStringVectorを含めるには、CVectorの引数を C++ ライブラリのメソッドに渡すメソッドを定義するヘッダー ファイルWrapperStringVector.hppを作成します。// 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; }StringVectorという名前のフォルダー内にライブラリ定義を生成します。clibgen.generateLibraryDefinition( ... ["StringVector.hpp","WrapperStringVector.hpp"], ... InterfaceName="StringVector", ... Libraries="StringVector.lib", ... TreatObjectPointerAsScalar=true, ... Verbose=true)
インターフェイスをビルドします。
build(defineWrapperStringVector) addpath('WrapperStringVector')ライブラリ ファイル
StringVector.dllをStringVectorフォルダーにコピーします。関数を呼び出します。
% 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;
Windows でのコンパイル済みライブラリ ファイルのビルド例
Windows のコマンド プロンプトで、MinGW-w64 コンパイラへのパスをシステム パスに追加します。たとえば、コンパイラが mingwpathname にある場合は、次を入力します。
set mingwpath = 'mingwpathname'; set PATH=%mingwpath%;%PATH%
C++ ソース ファイルの場所に移動します。
以下のコマンドを実行して、ソース ファイル からライブラリ ファイルを生成します。source.cpp
g++ -c source.cpp -o source.obj -std=c++11 g++ -shared -o source.dll source.obj -Wl,--out-implib,source.lib