www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Annoyance with function template unwrapping

reply solidstate1991 <laszloszeremi outlook.com> writes:
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.
Jan 16 2021
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
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.
Jan 16 2021
parent solidstate1991 <laszloszeremi outlook.com> writes:
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.
Jan 16 2021
prev sibling parent reply kdevel <kdevel vogtner.de> writes:
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.
Jan 17 2021
parent reply Paul Backus <snarwin gmail.com> writes:
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.
Jan 17 2021
parent reply kdevel <kdevel vogtner.de> writes:
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
Jan 17 2021
parent kdevel <kdevel vogtner.de> writes:
On Sunday, 17 January 2021 at 20:03:46 UTC, kdevel wrote:
 $ dmd temploverl
 $ ./temploverl
 2
Erratum: 1, not 2 is printed.
Jan 17 2021