Also sprach JustMe:
> Given:
>
> package x;
>
> sub new { return bless {}, $_[0]; }
>
> #-- callback() is call by the C++ class (reader_as_cpp_object)
> #-- whenever an event is detected.
>
> sub callback {
> my ($self, $ref_to_an_event_object) = @_;
> print $ref_to_an_event_object->data();
> }
>
> package main;
>
> use reader_as_cpp_object;
>
> my $x = x->new();
> my $reader = reader_as_cpp_object->new($x)
>
> $reader->read( 'afile.txt' ) # Reader is a reference to a C++ class
>
>
> I've got the callback working just fine. The problem I can't seem to
> solve, is how to pass the sub callback() a reference to a C++ object
> that was created by the C++ object reader_as_cpp_object.
Can you be more specific? You want $ref_to_an_event_object to
contain a pointer to a C++ object? This is easy. Do something like this
in your callback:
OBJECT *obj; // obj is the C++ object
...
SV *ref_to_obj = sv_newmortal();
sv_setref_pv(ref_to_object, "Class::Of::Reader", (void*)obj);
XPUSHs(ref_to_object); // push onto stack to pass to Perl callback
...
Your callback will now receive a scalar variable with an integer in it.
This integer is the address of the C++ object. To de-reference the
pointer and get the object back, you do:
OBJECT *obj = (OBJECT*)SvIV((SV*)SvRV(ref_to_object));
Usually, you put such things into a typemap file to let these
conversions happen authomatically:
# mapping from C++ objects to INPUT/OUTPUT objects
OBJECT * O_OBJECT
OUTPUT
O_OBJECT
sv_setref_pv( $arg, CLASS, (void*)$var );
INPUT
O_OBJECT
if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
$var = ($type)SvIV((SV*)SvRV( $arg ));
else{
warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
XSRETURN_UNDEF;
}
And now you can use that in your XSUBS very conveniently:
OBJECT *
function (obj)
OBJECT *obj;
PREINIT:
OBJECT *new_object;
CODE:
...
new_object = new OBJECT (args,...);
RETVAL = new_object;
OUTPUT:
RETVAL
So INPUT typemap kicks in when you pass your XSUB an appropriate
argument. 'OBJECT *obj' is such an argument and now Perl will convert
the SV* it receives into a pointer to OBJECT according to the
INPUT/O_OBJECT typemap. When returning 'OBJECT*', OUTPUT/O_OBJECT turns
a C++ object into a SV*.
When calling a Perl-callback however, you have to do this conversion
manually as I showed further above. You just copy the pointer (casted to
(void*) into an SV using sv_setref_pv(), at the same time blessing the
scalar variable into the appropriate package that should handle objects
of this type. Since your function read() operates on the C++ object,
bless it into the package where this method is defined. Use the INPUT
there and your Perl object is turned into a C++ again.
> I've read perlgut, perlapi, perlxs, perlxstut, cookbookA and
> cookbookB, and googled all day and I'm still no closer to a solution.
I was just about to recommend cookbookA and cookbookB, but you have
already read that. It's not exactly full of verbose explanations, it
just gives a few examples. Do they make more sense now? You could try to
re-read perlxs.pod, section "Using XS with C++".
Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus}) !JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexi ixesixeseg;y~\n~~dddd;eval
|