Thread overview
Annoyance with function template unwrapping
Jan 16, 2021
solidstate1991
Jan 16, 2021
Basile B.
Jan 16, 2021
solidstate1991
Jan 17, 2021
kdevel
Jan 17, 2021
Paul Backus
Jan 17, 2021
kdevel
Jan 17, 2021
kdevel
January 16, 2021
In one of my projects, I want to use function pointers that I get from a function template that has overloads. Easily reproducable example:

void func(ubyte b)(int i)
{
    writeln(__PRETTY_FUNCTION__);
}

void func(ubyte b)(float f)
{
    writeln(__PRETTY_FUNCTION__);
}
void main()
{
    void function(float) fp = &func!(5); // Error: template onlineapp.func matches more than one template declaration
}

However defining the function templates this way works:

template func(ubyte b) {
    void func(int i) {
        writeln(__PRETTY_FUNCTION__);
    }
    void func(float i) {
        writeln(__PRETTY_FUNCTION__);
    }
}

I might change my project CPUblit to fit to the latter, and then add unittests to ensure that it works, but I don't know whether it's a bug, some odd behavior, or something DIP-worthy.
January 16, 2021
On Saturday, 16 January 2021 at 22:09:48 UTC, solidstate1991 wrote:
> In one of my projects, I want to use function pointers that I get from a function template that has overloads. Easily reproducable example:
>
> void func(ubyte b)(int i)
> {
>     writeln(__PRETTY_FUNCTION__);
> }
>
> void func(ubyte b)(float f)
> {
>     writeln(__PRETTY_FUNCTION__);
> }
> void main()
> {
>     void function(float) fp = &func!(5); // Error: template onlineapp.func matches more than one template declaration
> }
>
> However defining the function templates this way works:
>
> template func(ubyte b) {
>     void func(int i) {
>         writeln(__PRETTY_FUNCTION__);
>     }
>     void func(float i) {
>         writeln(__PRETTY_FUNCTION__);
>     }
> }
>
> I might change my project CPUblit to fit to the latter, and then add unittests to ensure that it works, but I don't know whether it's a bug, some odd behavior, or something DIP-worthy.

It's not a bug. If you rewrite the function without the shorthand syntax then you realize that the error message is correct, there's indeed two "template func(){}". As a workaround,

you can build the overlaod set explicitly, e.g

  void func1(ubyte b)(float f) { }
  void func2(ubyte b)(int i) { }
  alias func = func1!5;
  alias func = func2!5;

or the same but "meta-programmatically"

  void f(ubyte b)(float f) { }
  void f(ubyte b)(int i) { }
  static foreach (o; __traits(getOverloads, mixin(__MODULE__), "func", true))
    alias func = o!5;

which allows to use a single ident for all the template func, although the overload set must be named differently.
January 16, 2021
On Saturday, 16 January 2021 at 23:19:41 UTC, Basile B. wrote:
> or the same but "meta-programmatically"
>
>   void f(ubyte b)(float f) { }
>   void f(ubyte b)(int i) { }
>   static foreach (o; __traits(getOverloads, mixin(__MODULE__), "func", true))
>     alias func = o!5;
>
> which allows to use a single ident for all the template func, although the overload set must be named differently.

This one didn't work for me, since it couldn't find the function once I tried to use them from an external package.
January 17, 2021
On Saturday, 16 January 2021 at 22:09:48 UTC, solidstate1991 wrote:

[...]

> However defining the function templates this way works:
>
> template func(ubyte b) {
>     void func(int i) {
>         writeln(__PRETTY_FUNCTION__);
>     }
>     void func(float i) {
>         writeln(__PRETTY_FUNCTION__);
>     }
> }

Fits.

> I might change my project CPUblit to fit to the latter, and then add unittests to ensure that it works, but I don't know whether it's a bug, some odd behavior, or something DIP-worthy.

It's odd behavior. It seems that in D template definitions are things
in itself (like a struct definition) which obey a one declaration (!) rule.

   template S (T) {
      void foo () {}
   }
   template S (T) {
      void bar () {}
   }

   auto fp = &S!int.bar;

depicts the programmer's intent in a crystal clear manner. Nonetheless dmd
yiels the error you encountered. I think that D-templates should behave like
C++ namespaces not like structs.
January 17, 2021
On Sunday, 17 January 2021 at 18:36:13 UTC, kdevel wrote:
>
> It's odd behavior. It seems that in D template definitions are things
> in itself (like a struct definition) which obey a one declaration (!) rule.

It's not exactly a one-declaration rule. Templates, like functions, can be overloaded:

template foo(T) {
    enum foo = "overload one";
}

template foo(T, U) {
    enum foo = "overload two";
}

static assert(foo!int == "overload one");
static assert(foo!(int, double) == "overload two");

As long as the overloads are unambiguous, there's no problem. As with functions, it's only when you have two overloads that match the same arguments that you get an error.
January 17, 2021
On Sunday, 17 January 2021 at 19:29:59 UTC, Paul Backus wrote:
[...]
> As long as the overloads are unambiguous, there's no problem. As with functions, it's only when you have two overloads that match the same arguments that you get an error.

And sometimes you don't get an error:

```temploverl.d
template S (U) { int x = 1; }
template S (U, V = void) { int x = 2; }

int main ()
{
   import std.stdio: writeln;
   writeln (S!(int).x);
   return 0;
}
```

$ dmd temploverl
$ ./temploverl
2

January 17, 2021
On Sunday, 17 January 2021 at 20:03:46 UTC, kdevel wrote:
> $ dmd temploverl
> $ ./temploverl
> 2

Erratum: 1, not 2 is printed.