###目次
C++を使ってRubyのメソッドを書く(その1) <- ここ
C++を使ってRubyのメソッドを書く(その2) ベンチマーク
SWIGを使うことで、C++で書いた関数をRubyのメソッドとして簡単に呼び出すことができます。文字列や配列もC++の関数に手を加えることなく使えるようになります。
###必要なファイル
関数の本体です。C++で書かれた普通の関数です。
#include <string>
#include <vector>
using namespace std;
int twicefold(int x);
double twicefold(double x);
vector<int> twicefold(vector<int> ary);
vector<double> twicefold(vector<double> ary);
class Test{
public:
static int sum(vector<int> ary);
static double sum(vector<double> ary);
static int length(string str);
static vector<int> length(vector<string> str_ary);
};
#include "test.hpp"
using namespace std;
int twicefold(int x){
return(x*2);
}
double twicefold(double x){
return(x*2.0);
}
vector<int> twicefold(vector<int> ary){
size_t ary_size=ary.size();
vector<int> twice_result(ary_size);
for(int i=0; i<ary_size; i++){
twice_result[i]=ary[i]*2;
}
return(twice_result);
}
vector<double> twicefold(vector<double> ary){
size_t ary_size=ary.size();
vector<double> twice_result(ary_size);
for(int i=0; i<ary_size; i++){
twice_result[i]=ary[i]*2.0;
}
return(twice_result);
}
int Test::sum(vector<int> ary){
int total=0;
for (int i=0; i<ary.size(); i++){
total+=ary[i];
}
return(total);
}
double Test::sum(vector<double> ary){
double total=0.0;
for (int i=0; i<ary.size(); i++){
total+=ary[i];
}
return(total);
}
int Test::length(string str){
return(str.length());
}
vector<int> Test::length(vector<string> str_ary){
size_t ary_size=str_ary.size();
vector<int> lengths(ary_size);
for(int i=0; i<ary_size; i++){
lengths[i]=Test::length(str_ary[i]);
}
return(lengths);
}
オーバーロードになっているものがいくつかありますが、引数のクラスに応じて適切な関数が呼ばれます。
次にSWIG用のファイルです。
%module testF
%{
#include "test.hpp"
%}
%include <std_string.i>
%include <std_vector.i>
%template(StringVector) std::vector<std::string>;
%template(IntVector) std::vector<int>;
%template(FloatVector) std::vector<double>;
%include test.hpp
引数や戻り値にvectorを使う時には上記のように%templateを追加してください。括弧内の名称はクラス名になります。
%include test.hppを%templateの後に移動しました。これにより引数や返値が自然な形で使えるようになりました。
require 'mkmf'
create_makefile("testF")
(2020.9.21) $libs += " -lstdc++ "を削除しました。不要な行でした。
以上のファイルを同じフォルダに入れておきます。
###ライブラリファイルを作成
swig -c++ -ruby test.i
ruby extconf.rb
make
1行目のコマンドでwarningが出ますが、正常にオーバーロードができているようです。
ここまでで、testF.bundle(OSにより拡張子は異なる)のファイルができます。
###テスト用のプログラム
require "./testF"
p TestF::twicefold(2)
p TestF::twicefold(3.2)
p TestF::twicefold([1,2,3])
p TestF::twicefold([2.1,3.2,4.3])
p TestF::Test.sum([1,2,3])
p TestF::Test.sum([2.1, 3.2, 4.3])
p TestF::Test.length("12345")
p TestF::Test.length(["12345", "678"])
CentOS 8.2 Ruby 2.6.6
macOS 10.13.6 Ruby 2.7.1
SWIG 4.0.2
Ruby 2.7ではswigのバージョン4.0.2以降が必要です。