Thread overview
this T / variadic template and interfaces
Oct 26, 2020
frame
Oct 26, 2020
Simen Kjærås
Oct 26, 2020
frame
Oct 26, 2020
Jacob Carlborg
Oct 27, 2020
frame
Oct 27, 2020
Jacob Carlborg
Oct 27, 2020
frame
Oct 27, 2020
frame
October 26, 2020
Did not find this topic:

I have an interface and some wrapper classes that use it. The wrapper's methods should accept variadic arguments. The runtime should only work with the interface, trying casting to a wrapper is not an option, because it's a plugin design.

- defining a variadic template in wrapper does not work, because we are working with the interface only and compiler complains method is not callable with argument X

- defining a variadic template without body in interface causes linker errors, which makes sense somehow

- defining a variadic template with body in interface could work if the compiler would get the right "this" type but sadly, "this" refers to interface and also "this T" refers to interface too.

Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible.

October 26, 2020
On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote:
> Did not find this topic:
>
> I have an interface and some wrapper classes that use it. The wrapper's methods should accept variadic arguments. The runtime should only work with the interface, trying casting to a wrapper is not an option, because it's a plugin design.
>
> - defining a variadic template in wrapper does not work, because we are working with the interface only and compiler complains method is not callable with argument X
>
> - defining a variadic template without body in interface causes linker errors, which makes sense somehow
>
> - defining a variadic template with body in interface could work if the compiler would get the right "this" type but sadly, "this" refers to interface and also "this T" refers to interface too.
>
> Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible.

Templates can't be virtual, so even if they can be defined in an interface, you can't override them in a class that implements said interface - the implementation needs to be in the interface itself.

This makes sense if you consider that the user of the interface has no knowledge of the types that implement it, and vice versa: the implementing class has no idea which instantiations to make, and the user has no idea which implementing classes to create instantiations for. Templates require that the user have full knowledge of the templates to be instantiated.

There are some workarounds of sorts, but they depend heavily on what you're trying to achieve. Can you use an array of std.variant.Variant, for instance?

--
  Simen
October 26, 2020
On Monday, 26 October 2020 at 11:48:48 UTC, Simen Kjærås wrote:
> 
>
> This makes sense if you consider that the user of the interface has no knowledge of the types that implement it, and vice versa: the implementing class has no idea which instantiations to make, and the user has no idea which implementing classes to create instantiations for. Templates require that the user have full knowledge of the templates to be instantiated.
>
> There are some workarounds of sorts, but they depend heavily on what you're trying to achieve. Can you use an array of std.variant.Variant, for instance?
>
> --
>   Simen

Yes, the user/coder does not know of other types by any chance. The interface must be used.

Well I guess I let the interface do the variadic stuff and pass the argument as Variant[] to the wrapper in a new interface method. Thanks.

October 26, 2020
On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote:

> Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible.

As Simen mentioned, templates cannot be virtual. But you don't need to use a template, you can use a regular variadic method [1]. It's a bit more clunky to work with than template variadic functions. Or if all the arguments will be of the same type, you can use type safe variadic functions [2], which are easier to work with.

[1] https://dlang.org/spec/function.html#d_style_variadic_functions
[2] https://dlang.org/spec/function.html#typesafe_variadic_functions

--
/Jacob Carlborg

October 27, 2020
On Monday, 26 October 2020 at 13:02:33 UTC, Jacob Carlborg wrote:
> On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote:
>
>> Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible.
>
> As Simen mentioned, templates cannot be virtual. But you don't need to use a template, you can use a regular variadic method [1]. It's a bit more clunky to work with than template variadic functions. Or if all the arguments will be of the same type, you can use type safe variadic functions [2], which are easier to work with.
>
> [1] https://dlang.org/spec/function.html#d_style_variadic_functions
> [2] https://dlang.org/spec/function.html#typesafe_variadic_functions
>
> --
> /Jacob Carlborg

Hmm, a question of design. Is there also a convenient way to pass the arguments to a template or get a Variant[] from it?
October 27, 2020
On Tuesday, 27 October 2020 at 09:40:33 UTC, frame wrote:

> Hmm, a question of design. Is there also a convenient way to pass the arguments to a template or get a Variant[] from it?

Convenient, no not that I know of. You can use a type safe variadic function that takes Variant, if you want to end up with Variant[] anyway. It depends on how you want the API to look like. Here are some examples:

void foo(...);
void bar(Variant[] args ...);

foo(3, "foo", 'a'); // pass in the arguments as is
bar(Variant(3), Variant("foo"), Variant('a')); // need to wrap each argument in Variant

The advantage of using the type safe variadic function is that all the arguments are bundle into one array, make it easier to work with.

--
/Jacob Carlborg

October 27, 2020
On Tuesday, 27 October 2020 at 10:41:06 UTC, Jacob Carlborg wrote:
> On Tuesday, 27 October 2020 at 09:40:33 UTC, frame wrote:
>
>> Hmm, a question of design. Is there also a convenient way to pass the arguments to a template or get a Variant[] from it?
>
> Convenient, no not that I know of. You can use a type safe variadic function that takes Variant, if you want to end up with Variant[] anyway. It depends on how you want the API to look like. Here are some examples:
>
> void foo(...);
> void bar(Variant[] args ...);
>
> foo(3, "foo", 'a'); // pass in the arguments as is
> bar(Variant(3), Variant("foo"), Variant('a')); // need to wrap each argument in Variant
>
> The advantage of using the type safe variadic function is that all the arguments are bundle into one array, make it easier to work with.
>
> --
> /Jacob Carlborg

I tried the (...) thing - I ran into access violation by passing a slice like:

if (_arguments[i] == typeid(ubyte[])) {
  auto foo = va_arg!(ubyte[])(_argptr);
}

The same is working with variadic template. I am missing something?


October 27, 2020
On Tuesday, 27 October 2020 at 11:30:53 UTC, frame wrote:
> On Tuesday, 27 October 2020 at 10:41:06 UTC, Jacob Carlborg wrote:
>
> if (_arguments[i] == typeid(ubyte[])) {
>   auto foo = va_arg!(ubyte[])(_argptr);
> }
>
> The same is working with variadic template. I am missing something?

Never mind, I was squeezing the argument list through a delegate but the actual method - thus the pointer was 0.