我正在为Editline编写绑定;它的函数之一history为库的这一部分完成了大部分工作,但是有几个可能的签名:
:(Pointer[Internal], Pointer[Event], int32 --> int32)
:(Pointer[Internal], Pointer[Event], int32, int32 --> int32)
:(Pointer[Internal], Pointer[Event], int32, Str --> int32)
# etc.第三个参数是一个标志,它决定history应该用给定的参数调用哪个函数,但是由于这些符号没有导出,所以我无法使用它们。我如何才能找到一种使用该函数的方法?我不能使用多个subs或使用cglobal将其转换为一个Pointer,然后转换为一个具有正确签名的函数。
编辑:我知道is symbol,但我想知道是否有更好的方法来解决这个问题,因为有9个不同的签名要写。
发布于 2020-02-26 19:55:36
可以用Raku函数包装本机函数:
sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag, $c? --> int32 ){
given $flag {
when 0|2 {
sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
history( $a, $b, $flag )
}
when 1|3 {
sub history (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(…) {}
history( $a, $b, $flag, $c )
}
when 4 {
sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
history( $a, $b, $flag, $c )
}
}
}或者,您可以将每个版本封装在自己的多个版本中:
# Note the flag value ---------------------------------------+
# |
# V
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, 0 --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
history( $a, $b, 0 )
}
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, 2 --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
history( $a, $b, 2 )
}
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag where 1|3, int32 $c --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(…) {}
history( $a, $b, $flag, $c )
}
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, 4, Str:D $c --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
history( $a, $b, 4, $c )
}您甚至可以根据参数确定要给出的正确标志。只有当每个签名只有一个标志时,这才会起作用。
(因此,下面的示例不遵循0和2具有相同签名的上述示例。)
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
history( $a, $b, 0 )
}
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $c --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
history( $a, $b, 1, $c )
}
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, Str:D $c --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
history( $a, $b, 4, $c )
}您可以用不同的名称编写包装:
sub foo ( Pointer[Internal] $a, Pointer[Event] $b --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
history( $a, $b, 0 )
}
sub bar ( Pointer[Internal] $a, Pointer[Event] $b, int32 $c --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
history( $a, $b, 1, $c )
}
sub baz ( Pointer[Internal] $a, Pointer[Event] $b, Str:D $c --> int32 ){
sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
history( $a, $b, 4, $c )
}通过使用is symbol,您可以在不使用包装器的情况下做到这一点。
sub foo (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) is symbol<history> {}
sub bar (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(…) is symbol<history> {}
sub baz (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) is symbol<history> {}还可以在包装器函数中使用nativecast和生成的签名对象:
sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag, $c? --> int32 ){
my \I32 = Parameter.new( type => int32 );
my \PI = Parameter.new( type => Pointer[Internal] );
my \PE = Parameter.new( type => Pointer[Event] );
my \STR = Parameter.new( type => Str );
my @params = ( PI, PE, I32 );
given $flag {
when 0|2 {
}
when 1|3 {
@params.push( I32 );
}
when 4 {
@params.push( STR );
}
}
my \signature = Signature.new( params => @params.List, returns => int32 );
# fill this out -----------V
my \history-ptr = cglobal( …, 'history', Pointer );
my &history = nativecast( signature, history-ptr );
history( $a, $b, $flag, ($c if +@params == 4) );
}这就是您如何为C的printf或scanf编写包装器的方式。
不管您使用的是哪一种,您都需要某种方式来确定您需要调用哪种变体。
即使在C中,也必须根据当前参数或以前的参数来确定参数的数量和类型。
在printf中,参数的数量和类型基于第一个参数,即格式。
C函数可以通过具有尾尾null参数来确定参数的数量。在这种情况下,你必须告诉Raku。
不管底层外部函数如何处理va_args,您都必须以某种形式将该算法复制到Raku中。它不能只是猜测。
如果有几个功能类似的外部函数,则可以为它们创建一个包装器生成器。
https://stackoverflow.com/questions/49586031
复制相似问题