Perl xs - cannot return a new C ++ user object from a method call - returns a scalar value instead

In my XS file, I have:

Like my new method:

matrix * matrix::new( size_t ncols, size_t nrows ) 

which returns a matrix object as it should, and I can call methods.

Then I have a method call that creates a new matrix object and should return it as a new matrix:

 matrix * matrix::getInnerMatrix( ) PREINIT: char * CLASS = (char *)SvPV_nolen(ST(0)); CODE: RETVAL = static_cast<matrix*>(THIS->matrix::getInnerMatrix()); OUTPUT: RETVAL 

However, the return type is matrix=SCALAR(0x122f81c) , and therefore I cannot call method calls from this object, since the perl interpreter seems to look at the return type as a type of scalar value instead of the 'matrix' object. Here is the test script:

 $m1 = matrix::new(matrix,4,4); @arr = ( 1 .. 16 ); $aref = [@arr]; $m1->assign_aref($aref); my $m2 = $m1->getInnerMatrix(); print ref $m1; # returns "matrix" (like it should) print "\n\n"; print ref $m2; # returns "matrix=SCALAR(0x122f81c)" (wrong) 

Here is my map:

 TYPEMAP matrix * O_MATRIX OUTPUT O_MATRIX sv_setref_pv( $arg, CLASS, (void*)$var ); INPUT O_MATRIX if ( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) { $var = ($type)SvIV((SV*)SvRV( $arg )); } else { warn( \"${Package}::$func_name() -- ${var} not a blessed SV reference\" ); XSRETURN_UNDEF; } 

What changes should I make to my XS file or any other file to ensure that a clean matrix object is returned?

+7
c ++ perl xs
source share
1 answer

When using XS with C ++, the XS preprocessor inserts THIS , for example, methods and CLASS for static methods. A method called new is considered a static method. This allows you to use xsubs as instance methods / class methods by default: matrix->new and $m->getInnerMatrix() .

Your sample map uses the CLASS variable, which is not provided for instance methods. In your case, I would hard code the package name in the type map:

 OUTPUT O_MATRIX sv_setref_pv( $arg, "matrix", (void*)$var ); 

A type map is also used when an argument of this type is not used as an invocant. For example. consider this xsub:

 matrix* some_other_xsub(x) int x 

There will not be a CLASS variable for the return value of matrix* .

Please note that lowercase names should only be used for pragma packages (e.g. strict or warnings ). Use CamelCase for your classes.

Your attempt to provide your own value for CLASS failed because SvPV_nolen() builds the link and does not get the reference type. That is, it is equivalent to "$m" , not ref $m . A more suitable alternative would be to use sv_ref() :

 char* CLASS = SvPV_nolen(sv_ref(NULL, THIS, true)); 

The third parameter sv_ref() makes this function work as a Perl ref function, i.e. returns the name of the class if the scalar is blissful, and not just the base type of the link.

+4
source share

All Articles