Why can't I get swig wrap std::vector to Ruby class?
I have an application with an embedded Ruby interpreter, and interfaces to STL classes generated by swig. Pretty much everything worked out fine thanks to swig, except for one thing:
%module Stuff
%import "std_vector.i"
namespace std
{
%template(Vectord) vector<double>;
};
%inline%{
std::vector<开发者_JS百科double> test;
%}
When I try to use this in Ruby the type Stuff::Vectord
exists, but it is not the return type of the generated singleton method test. Looking at the generated C wrapper file I can see the class Vectord
and its methods getting defined, but looking at _wrap_test_get
I do not see anything returning sth
of class Stuff::Vectord
.
What do I have to do to get test
typed as Vectord
?
First, you are correct. The ruby generated Stuff::test
object is not of type Vectord
.
However, it is of a type that behaves exactly like Vectord
which is the most important question for a duck typed language like Ruby.
Correction to Stuff.i
There is one minor problem in your example. The %import <stl_vector.i>
statement should be %include <stl_vector.i>
.
The correct complete example is:
%module Stuff
%include "std_vector.i"
namespace std
{
%template(Vectord) vector<double>;
};
%inline%{
std::vector<double> test;
%}
Building the Module
The swig wrapper can be generated with
swig -ruby -c++ Stuff.i
And compiled (with g++) with the statement:
g++ Stuff_wrap.cxx -shared -fPIC -o Stuff.so -I /usr/lib/ruby/1.8/x86_64-linux/
Using the Module
jason@jason-VirtualBox:~$ irb
irb(main):001:0> require 'Stuff'
=> true
irb(main):003:0> Stuff::test.class
=> Array
As we can see, the object returned by Stuff::test
is of type Array
. However, unlike a regular Ruby array, this array can only be set to a value that is convertible to a std::vector<double>
irb(main):002:0> Stuff::test = [5,4,3]
=> [5, 4, 3]
irb(main):003:0> Stuff::test = [5.0, "5.0"]
TypeError: double
from (irb):3:in `test='
from (irb):3
from :0
Also, it can be converted directly to and from std::vector<double>
objects.
irb(main):002:0> vec = Stuff::Vectord.new()
=> std::vector<double,std::allocator< double > > []
irb(main):003:0> vec << 5.0
=> 5.0
irb(main):004:0> vec << 2.3
=> 2.3
irb(main):005:0> vec
=> std::vector<double,std::allocator< double > > [5.0,2.3]
irb(main):006:0> Stuff::test = vec
=> std::vector<double,std::allocator< double > > [5.0,2.3]
irb(main):007:0> vec2 = Stuff::Vectord.new(Stuff::test)
=> std::vector<double,std::allocator< double > > [5.0,2.3]
irb(main):008:0> Stuff::test.class
=> Array
irb(main):009:0> vec2.class
=> Stuff::Vectord
irb(main):010:0> Stuff::test
=> [5.0, 2.3]
Other SWIG Targets
It's important to note that the statically typed SWIG targets of C# and Java produce the results you were expecting. If you ever have a question about how your types are being handled in a SWIG output, it is almost always a good idea to compare the C# or Java output against what you are expecting.
Conclusion
While Stuff::test
and Vectord
are two different types, they both are arrays that can only store doubles.
They are almost indistinguishable inside of the Ruby code. The code produced does exactly what you want it to do.
精彩评论