このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
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; } }; #endif
CStack
クラスを使用して関数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"], ... PackageName="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; } }; #endif
Pairs
クラスを含めるには、次のラッパー ヘッダー ファイル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"], ... PackageName="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"], ... PackageName="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; } }; #endif
readStringVector
と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"], ... PackageName="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