質問編集履歴

2 想定通りに動かなかったソースを追記

KureteRubyLua

KureteRubyLua score 194

2017/08/19 12:38  投稿

Ruby(mruby)とvector等のC++のSTLを連携させるには?
Ruby(mruby)とC++を連携させようと考えています。
int等、C++のプリミティブ型や関数、クラスを連携させるのは
[mrubybind]( https://github.com/ktaobo/mrubybind)という外部のソースコードを
借りる形で出来たのですが、std::vector等のstlの連携がmrubybindを改造しても
上手く出来ません。
例えば以下のソースコードを実現できません。
```Ruby
#A_DataはCと連携させたクラス
data=A_Data.new()
#b_arrayはA_Dataの中にあるstd::vector<int>型の変数
#b_arrayに添字を添え、中身を表示する事はできる
print data.b_array[0]
#data.b_array[0]にbufを代入しているが、何故か代入できない
buf=99;
data.b_array[0]=buf;
```
mrubyのバインドは通常のRubyとcの連携に似ている事は分かったので
おそらく通常のRubyとCの連携においてSTLをバインドする
方法がわかれば、そのままmrubyでも転用できると考えているのですが
全くやり方が分かりません。
上記のソースコードが実現できるようにRubyとSTLをバインドするには
どうすれば良いのでしょうか?mrubyにおいてmrubybindを使わずに
連携させる方法については下記に書かれています
[http://qiita.com/cubicdaiya/items/fc0620c7b9629bb85d6f]( http://qiita.com/cubicdaiya/items/fc0620c7b9629bb85d6f)
もし足りない部分があれば質問をお願いします。よろしくお願いします。
追記
ソースコードをaxfcにアップしました。
https://www.axfc.net/u/3835671
改造した部分のみを書くと、こうなります。
```C++
   //改造ここから
   //独自クラスでも扱えるように改造
   template<typename T>
   struct Type {
       static T(*SetFunc)(mrb_state* mrb, mrb_value v);
       static mrb_value(*RetFunc)(mrb_state* mrb, T& p);
       static const char* TYPE_NAME;
       static int check(mrb_state* mrb, mrb_value v) { return mrb_class_ptr(v) != nullptr; }
       static T get(mrb_state* mrb, mrb_value v)
       {
           return SetFunc(mrb, v);
       }
       static mrb_value ret(mrb_state* mrb, T& p)
       {
           return RetFunc(mrb, p);
       }
   };
   template<typename T>
   T(*Type<T>::SetFunc)(mrb_state* mrb, mrb_value v);
   template<typename T>
   mrb_value(*Type<T>::RetFunc)(mrb_state* mrb, T& p);
   template<typename T>
   const char* Type<T>::TYPE_NAME;
   //Vectorを扱えるように改造
   template<typename T>
   struct Type<std::vector<T>> {
       static const char* TYPE_NAME;
       static int check(mrb_state* mrb, mrb_value v) { return mrb_array_p(v); }
       static std::vector<T> get(mrb_state* mrb, mrb_value v)
       {
           std::vector<T> indexes;
           int len_i = RARRAY_LEN(v);
           indexes.resize(len_i);
           for (int i = 0; i < len_i; ++i)
           {
               indexes.push_back(static_cast<T>(Type<T>::get(mrb, v)));
           }
           return indexes;
       }
       static mrb_value ret(mrb_state* mrb, std::vector<T> p)
       {
           mrb_value foo = mrb_ary_new(mrb);
           for (int i = 0; i < p.size(); ++i)
           {
               mrb_ary_push(mrb, foo, Type<T>::ret(mrb, p[i]));
           }
           return foo;
       }
   };
   template<typename T>
   const char* Type<std::vector<T>>::TYPE_NAME = "Array";
   //Vector
   template<typename T>
   struct Type<std::vector<T>&> {
       static const char* TYPE_NAME;
       static int check(mrb_state* mrb, mrb_value v) { return mrb_array_p(v); }
       static std::vector<T> get(mrb_state* mrb, mrb_value v)
       {
           std::vector<T> indexes;
           int len_i = RARRAY_LEN(v);
           indexes.resize(len_i);
           for (int i = 0; i < len_i; ++i)
           {
               indexes.push_back(static_cast<T>(Type<T>::get(mrb, v)));
           }
           return indexes;
       }
       static mrb_value ret(mrb_state* mrb, std::vector<T> p)
       {
           mrb_value foo = mrb_ary_new(mrb);
           for (int i = 0; i < p.size(); ++i)
           {
               mrb_ary_push(mrb, foo, Type<T>::ret(mrb, p[i]));
           }
           //return mrb_ary_value(&p);
           return foo;
       }
   };
   template<typename T>
   const char* Type<std::vector<T>&>::TYPE_NAME = "Array";
   //改造ここまで
//中略
   //改造ここから
   template <class T>
   void bind_set_func(T(*SetFunc)(mrb_state* mrb, mrb_value v)) {
       Type<T>::SetFunc = SetFunc;
   }
   template <class T>
   void bind_ret_func(mrb_value(*RetFunc)(mrb_state* mrb, T& p)) {
       Type<T>::RetFunc = RetFunc;
   }
コード
```
問題点はRubyの部分に書いたとおりで、C++で作ったクラスを用いて
作った変数の中にあるVectorの配列の一要素を代入できないという事です。
もし、他に問題点や聞きたい事があれば指摘をお願いします。
もし、他に問題点や聞きたい事があれば指摘をお願いします。
二回目の追記
想定通りに動かないRubyのソースを書きました。このソースを通すと「0,99」と表示されるはずが「0,0」と表示されてしまいます。
```Ruby
#A_DataはCと連携させたクラス
data=A_Data.new()
#b_arrayはA_Dataの中にあるstd::vector<int>型の変数
#b_arrayに添字を添え、中身を表示する事はできる
p data.b_array[0]
#data.b_array[0]にbufを代入しているが、何故か代入できない
buf=99;
data.b_array[0]=buf;
p data.b_array[0]
```
上のRubyのA_DataはC++で作成した独自クラスをRubyにバインドした物です。
下のような形でバインドせずに通すとエラーが起きるのでご注意下さい。
```C++
#include <vector>
#include "mrubybind.h"
class AData
{
  protected:
      std::vector<int> b_array;
  public:
      AData()
      {
          b_array.resize(1);
          b_array[0] = 0;
      };
      std::vector<int>& GetBArray()
      {
          return b_array;
      }
      void SetBArray(std::vector<int> set)
      {
          b_array=set;
      }
      virtual ~AData(){};
};
AData* newAData()
{
   return new AData();
}
void installADataClass(mrb_state* mrb)
{
   mrubybind::MrubyBind b(mrb);
   mrubybind::Type<AData>::TYPE_NAME = "A_Data";
   b.bind_class("A_Data", newAData);
   b.bind_instance_method("A_Data", "b_array", &AData::GetBArray);
   b.bind_instance_method("A_Data", "b_array=", &AData::SetBArray);
}
int main(int argc, char *argv[])
{
   // ファイルを開く
   const char* fn = "hoge.rb";
   std::shared_ptr< FILE > file(fopen(fn, "r"), [](FILE* f) { if (f != nullptr) { fclose(f); } });
   // エラー処理は程々に
   if (file == nullptr) {
       std::cout << "Load " << fn << " failed." << std::endl;
       return 1;
   }
   // 仮想マシンを初期化して
   std::shared_ptr< mrb_state > mrb(mrb_open(), [](mrb_state* p) { if (p != nullptr) { mrb_close(p); } });
   // 一時オブジェクトがつくられるのでGC arenaを保存
   int ai = mrb_gc_arena_save(mrb.get());
   mrbc_context *context = mrbc_context_new(mrb.get());
   installADataClass(mrb.get());
   // 実行する ("Hello, World!" が出る)
   mrb_load_file(mrb.get(), file.get());
   if (mrb->exc) {
       mrb_value exc = mrb_obj_value(mrb->exc);
       // エラー内容を取得
       mrb_value backtrace = mrb_get_backtrace(mrb.get());
       puts(mrb_str_to_cstr(mrb.get(), mrb_inspect(mrb.get(), backtrace)));
       // バックトレースを取得
       mrb_value inspect = mrb_inspect(mrb.get(), exc);
       puts(mrb_str_to_cstr(mrb.get(), inspect));
       // 例外をクリア
       mrb->exc = 0;
   }
   mrb_gc_arena_restore(mrb.get(), ai);
   mrbc_context_free(mrb.get(), context);
   return 0;
}
```
  • C++

    6384 questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • C

    6693 questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • Ruby

    13903 questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

1 ソースコードの改造した部分を追記、問題点について更新

KureteRubyLua

KureteRubyLua score 194

2017/08/18 07:27  投稿

Ruby(mruby)とvector等のC++のSTLを連携させるには?
Ruby(mruby)とC++を連携させようと考えています。
int等、C++のプリミティブ型や関数、クラスを連携させるのは
[mrubybind]( https://github.com/ktaobo/mrubybind)という外部のソースコードを
借りる形で出来たのですが、std::vector等のstlの連携がmrubybindを改造しても
上手く出来ません。
例えば以下のソースコードを実現できません。
```Ruby
#A_DataはCと連携させたクラス
data=A_Data.new()
#b_arrayはA_Dataの中にあるstd::vector<int>型の変数
#b_arrayに添字を添え、中身を表示する事はできる
print data.b_array[0]
#data.b_array[0]にbufを代入しているが、何故か代入できない
buf=99;
data.b_array[0]=buf;
```
mrubyのバインドは通常のRubyとcの連携に似ている事は分かったので
おそらく通常のRubyとCの連携においてSTLをバインドする
方法がわかれば、そのままmrubyでも転用できると考えているのですが
全くやり方が分かりません。
上記のソースコードが実現できるようにRubyとSTLをバインドするには
どうすれば良いのでしょうか?mrubyにおいてmrubybindを使わずに
連携させる方法については下記に書かれています
[http://qiita.com/cubicdaiya/items/fc0620c7b9629bb85d6f]( http://qiita.com/cubicdaiya/items/fc0620c7b9629bb85d6f)
もし足りない部分があれば質問をお願いします。よろしくお願いします。
もし足りない部分があれば質問をお願いします。よろしくお願いします。
追記
ソースコードをaxfcにアップしました。
https://www.axfc.net/u/3835671
改造した部分のみを書くと、こうなります。
```C++
   //改造ここから
   //独自クラスでも扱えるように改造
   template<typename T>
   struct Type {
       static T(*SetFunc)(mrb_state* mrb, mrb_value v);
       static mrb_value(*RetFunc)(mrb_state* mrb, T& p);
       static const char* TYPE_NAME;
       static int check(mrb_state* mrb, mrb_value v) { return mrb_class_ptr(v) != nullptr; }
       static T get(mrb_state* mrb, mrb_value v)
       {
           return SetFunc(mrb, v);
       }
       static mrb_value ret(mrb_state* mrb, T& p)
       {
           return RetFunc(mrb, p);
       }
   };
   template<typename T>
   T(*Type<T>::SetFunc)(mrb_state* mrb, mrb_value v);
   template<typename T>
   mrb_value(*Type<T>::RetFunc)(mrb_state* mrb, T& p);
   template<typename T>
   const char* Type<T>::TYPE_NAME;
   //Vectorを扱えるように改造
   template<typename T>
   struct Type<std::vector<T>> {
       static const char* TYPE_NAME;
       static int check(mrb_state* mrb, mrb_value v) { return mrb_array_p(v); }
       static std::vector<T> get(mrb_state* mrb, mrb_value v)
       {
           std::vector<T> indexes;
           int len_i = RARRAY_LEN(v);
           indexes.resize(len_i);
           for (int i = 0; i < len_i; ++i)
           {
               indexes.push_back(static_cast<T>(Type<T>::get(mrb, v)));
           }
           return indexes;
       }
       static mrb_value ret(mrb_state* mrb, std::vector<T> p)
       {
           mrb_value foo = mrb_ary_new(mrb);
           for (int i = 0; i < p.size(); ++i)
           {
               mrb_ary_push(mrb, foo, Type<T>::ret(mrb, p[i]));
           }
           return foo;
       }
   };
   template<typename T>
   const char* Type<std::vector<T>>::TYPE_NAME = "Array";
   //Vector
   template<typename T>
   struct Type<std::vector<T>&> {
       static const char* TYPE_NAME;
       static int check(mrb_state* mrb, mrb_value v) { return mrb_array_p(v); }
       static std::vector<T> get(mrb_state* mrb, mrb_value v)
       {
           std::vector<T> indexes;
           int len_i = RARRAY_LEN(v);
           indexes.resize(len_i);
           for (int i = 0; i < len_i; ++i)
           {
               indexes.push_back(static_cast<T>(Type<T>::get(mrb, v)));
           }
           return indexes;
       }
       static mrb_value ret(mrb_state* mrb, std::vector<T> p)
       {
           mrb_value foo = mrb_ary_new(mrb);
           for (int i = 0; i < p.size(); ++i)
           {
               mrb_ary_push(mrb, foo, Type<T>::ret(mrb, p[i]));
           }
           //return mrb_ary_value(&p);
           return foo;
       }
   };
   template<typename T>
   const char* Type<std::vector<T>&>::TYPE_NAME = "Array";
   //改造ここまで
//中略
   //改造ここから
   template <class T>
   void bind_set_func(T(*SetFunc)(mrb_state* mrb, mrb_value v)) {
       Type<T>::SetFunc = SetFunc;
   }
   template <class T>
   void bind_ret_func(mrb_value(*RetFunc)(mrb_state* mrb, T& p)) {
       Type<T>::RetFunc = RetFunc;
   }
コード
```
問題点はRubyの部分に書いたとおりで、C++で作ったクラスを用いて
作った変数の中にあるVectorの配列の一要素を代入できないという事です。
もし、他に問題点や聞きたい事があれば指摘をお願いします。
  • C++

    6384 questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • C

    6693 questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • Ruby

    13903 questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る