Using C++ Member Function with rb_protect

I'm having problems using a C++ member function with rb_protect. Here is the code:

class Sandbox {
public:
     Sandbox() {
         sandbox_ = rb_funcall(rb_const_get(rb_cObject, rb_intern("Sandbox")),
                               rb_intern("safe"),
                               0);
     }
     virtual ~Sandbox() {
     }
     VALUE eval(char * code) {
         int status = 0;
         VALUE val = rb_protect(&Sandbox::eval_protect,
                                rb_str_new2(code),
                                &status);
         if (status) { /* handle error... */ }
         return val;
     }
private:
     VALUE eval_protect(VALUE code) {
         return rb_funcall(sandbox_, rb_intern("eval"), 1, code);
     }
     VALUE sandbox_;
};

The compile fails with:

test.cpp: In member function ‘VALUE Sandbox::eval(char*)’:
test.cpp:18: error: cannot convert ‘VALUE (Sandbox::*)(VALUE)’ to ‘VALUE (*)(VALUE)’ for argument ‘1’ to ‘VALUE rb_protect(VALUE (*)(VALUE), VALUE, int*)’

$ ruby1.8 -v
ruby 1.8.5 (2006-08-06) [powerpc-darwin8.7.0]
$ g++ --version
powerpc-apple-darwin8-g++-4.0.1 (GCC) 4.0.1 (Apple Computer, Inc. build 5341)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Any ideas?

Thanks,
-- Daniel

What happens if you remove the & in this line:

VALUE val = rb_protect(&Sandbox::eval_protect,

···

On 8/8/06, Daniel Harple <dharple@generalconsumption.org> wrote:

I'm having problems using a C++ member function with rb_protect. Here
is the code:

Any ideas?

I'm not sure if it will help, but for my C++ extensions, I've had to do this type of trickery:

typedef VALUE (ruby_method)(...);

when doing this:

rb_define_method(some_ruby_object, "initialize", (ruby_method*) &some_object_initialize, 0);

Any ideas?

Also, have you tried casting to a void * ?

I get this compile error:

test.cpp: In member function ‘VALUE Sandbox::eval(char*)’:
test.cpp:15: error: argument of type ‘VALUE (Sandbox::)(VALUE)’ does not match ‘VALUE (*)(VALUE)’

-- Daniel

···

On Aug 8, 2006, at 4:45 PM, Francis Cianfrocca wrote:

What happens if you remove the & in this line:

VALUE val = rb_protect(&Sandbox::eval_protect,

Is it possible to make Sandbox::eval_protect a static function? Because as
an instance method, it's prototype is not VALUE(*)(VALUE) but rather
something like VALUE(*)(Sandbox&, VALUE).

···

On 8/8/06, Daniel Harple <dharple@generalconsumption.org> wrote:

On Aug 8, 2006, at 4:45 PM, Francis Cianfrocca wrote:

> What happens if you remove the & in this line:
>
> VALUE val = rb_protect(&Sandbox::eval_protect,

I get this compile error:

test.cpp: In member function 'VALUE Sandbox::eval(char*)':
test.cpp:15: error: argument of type 'VALUE (Sandbox::)(VALUE)' does
not match 'VALUE (*)(VALUE)'

-- Daniel

Of course it won't work that way, being a member function (it is given a
reference to this too...).

You'd have to do something like this (it's been a while without writing any
C++, so take this with a grain of salt):

class Sandbox {
public:
     Sandbox() {
         sandbox_ = rb_funcall(rb_const_get(rb_cObject, rb_intern("Sandbox")),
                               rb_intern("safe"),
                               0);
     }
     virtual ~Sandbox() {
     }
     VALUE eval(char * code) {
         int status = 0;
   VALUE args[2];
   args[0] = (VALUE)this;
   args[1] = rb_str_new2(code);
         VALUE val = rb_protect(&call_eval_protect, (VALUE)args, &status);
         if (status) { /* handle error... */ }
         return val;
     }
private:
     static VALUE call_eval_protect(VALUE args) {
       Sandbox *me = ((Sanbox *)args)[0];
       VALUE code = ((VALUE *)args)[1];
       return rb_funcall(me->sandbox_, rb_intern("eval"), 1, code);
     }
     VALUE sandbox_;
};

···

On Wed, Aug 09, 2006 at 05:57:53AM +0900, Daniel Harple wrote:

On Aug 8, 2006, at 4:45 PM, Francis Cianfrocca wrote:

>What happens if you remove the & in this line:
>
>VALUE val = rb_protect(&Sandbox::eval_protect,

I get this compile error:

test.cpp: In member function ‘VALUE Sandbox::eval(char*)’:
test.cpp:15: error: argument of type ‘VALUE (Sandbox::)(VALUE)’ does
not match ‘VALUE (*)(VALUE)’

--
Mauricio Fernandez - http://eigenclass.org - singular Ruby

Of course it won't work that way, being a member function (it is given a
reference to this too...).

You'd have to do something like this (it's been a while without writing any
C++, so take this with a grain of salt):

Thanks, I ended up with something similar.

class Sandbox
{
public:
     Sandbox() {
         sandbox_ = rb_funcall(rb_const_get(rb_cObject, rb_intern("Sandbox")),
                               rb_intern("safe"),
                               0);
     }
     virtual ~Sandbox() { }
     VALUE eval(char * code) {
         int status = 0;
         VALUE args[2];
         args[0] = reinterpret_cast<VALUE>(this);
         args[1] = rb_str_new2(code);
         VALUE val = rb_protect(eval_protect,
                                reinterpret_cast<VALUE>(args),
                                &status);
         if (status) { }
         return val;
     }

     VALUE & sandbox() {
         return sandbox_;
     }
private:
     VALUE sandbox_;
     static VALUE eval_protect(VALUE data) {
         VALUE *args = reinterpret_cast<VALUE *>(data);
         return rb_funcall(reinterpret_cast<Sandbox *>(args[0])- >sandbox(),
                           rb_intern("eval"),
                           1,
                           args[1]);
     }
};

-- Daniel

···

On Aug 8, 2006, at 5:34 PM, Mauricio Fernandez wrote:

Specifically, VALUE (Sandbox::*)(VALUE). Pointers to non-static methods
are actually a totally separate family of types to function pointers and
cannot be called without first using the .* or ->* operators to "bind"
them. This is similar to the difference between UnboundMethod and
Proc/Method in Ruby.

-mental

···

On Wed, 2006-08-09 at 06:03 +0900, Francis Cianfrocca wrote:

Is it possible to make Sandbox::eval_protect a static function? Because as
an instance method, it's prototype is not VALUE(*)(VALUE) but rather
something like VALUE(*)(Sandbox&, VALUE).