Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Re^2: Can't create XSUBs for C functions with a same name

by davido (Archbishop)
on Aug 23, 2012 at 21:00 UTC ( #989382=note: print w/replies, xml ) Need Help??

in reply to Re: Can't create XSUBs for C functions with a same name
in thread Can't create XSUBs for C functions with a same name

Let's say the user has two (or more) functions that are overloaded (C++ obviously), and that it's not trivial to implement them as a single variable-parameter function. Obviously XS can't deal with overloaded functions -- it's just too much a C++ thing. But there is another hope, and one that's often used when using Inline::C or Inline::CPP to interface with external libraries: Write a wrapper function.

Another limitation of Inline::CPP is that you can't expose templates directly to Perl. As with function overloading, Perl XS would have no idea what to do with template definitions. And C++ wouldn't know how Perl intends to call the functions, and thus wouldn't be able to expand the templates at compile-time. But once again, simple wrappers can easily hide templates from Perl/XS.

Ok, we're not dealing with templates here... just overloading. Either way the following will work. Write a wrapper that accepts a variable argument list, and then dispatches a call to the overloaded functions based on how many args are provided. It's a little cumbersome once you get more than a handful of variations to deal with, but I don't think people generally create more than a handful of overloads anyway (they just turn to templates, which is why I mentioned templates earlier).

So here's a hybrid: The overloaded functions (which won't bind to Perl), and the wrapper (which will):

use strict; use warnings; use v5.16; use Inline CPP => 'DATA'; say multiadd( 1 ); # No dispatch; just return the value. say multiadd( 1, 2 ); # Dispatch add( int, int ). say multiadd( 1, 2, 3 ); # Dispatch add( int, int, int ). say multiadd( 1, 2, 3, 4 ); # No dispatch; throw an exception. __DATA__ __CPP__ #include <stdexcept> // Overloaded functions: add(int,int), add(int,int,int): No (reliable* +) Perl binding. int add ( int a, int b ) { return a + b; } int add ( int a, int b, int c ) { return a + b + c; } // XS binding will be generated for multiadd(). int multiadd ( SV * a, ... ) { dXSARGS; try{ switch ( items ) { case 1: return SvIV(ST(0)); case 2: return add( SvIV(ST(0)), SvIV(ST(1)) ); case 3: return add( SvIV(ST(0)), SvIV(ST(1)), SvIV(ST(2)) ); default: throw std::runtime_error( "multiadd() - Too many args in function call" ); } } catch ( std::runtime_error msg ) { croak( msg.what() ); // Perl wants exceptions via croak. } }

This same approach could be used to dispatch calls based on any function signature criteria; number of parameters, or data-types. Additionally, a similar approach works for dispatching to template-generated functions or classes.

*(reliable): I think the last overload defined will bind via XS, but the others will be masked. It's not worth even trying to call directly.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://989382]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (6)
As of 2018-04-22 19:08 GMT
Find Nodes?
    Voting Booth?