Getting the overload set of a template

Arafel er.krali at gmail.com
Mon Apr 23 17:46:10 UTC 2018


On Monday, 23 April 2018 at 16:52:11 UTC, Alex wrote:
> On Monday, 23 April 2018 at 16:16:09 UTC, Arafel wrote:
>> ```
>> import std.meta;
>>
>> void main()
>> {
>>     pragma(msg, __traits(getMember, A, "Foo1").stringof); // 
>> Foo1(int N) if (N & 1)
>>     pragma(msg, __traits(getAttributes, __traits(getMember, A, 
>> "Foo1"))[0]); // tuple("int", "odd")
>>     alias f1a = Instantiate!(__traits(getMember, A, "Foo1"), 
>> 1); // This is expected
>>     pragma(msg, f1a); // A
>>     alias f1b = Instantiate!(__traits(getMember, A, "Foo1"), 
>> "+"); // Why would I know that I can even instantiate?? Also, 
>> can I haz UDA plz?
>>     pragma(msg, f1b); // B
>> }
>>
>> class A {
>>     @("int", "odd")
>> 	template Foo1(int N) if (N & 1)    {
>>         enum Foo1 = "A";
>>     }
>>     @("string", "+")
>> 	template Foo1(string op) if (op == "+") {
>>         enum Foo1 = "B";
>>     }
>> }
>> ```
>
> I'm not arguing about the case of different interfaces. It is 
> more or less ok, as from different argument types it will be 
> unambiguous which template will be instantiated. It is the case 
> of differentiating templates by their structure and/or 
> constraints.
>
> In this case, it is almost sure, that more then one form of 
> implementation exists. However, the forms will yield the same 
> semantic result. And I'm wondering why the implementation form 
> alone leads to differentiation.

Well, with templates the overload resolution must be always 
unambiguous:

```
import std.stdio;
void main()
{
	pragma(msg, A.Foo1!2);
	pragma(msg, A.Foo1!3);
	static assert(!is (typeof(A.Foo1!6))); // Compilation failure if 
there is any ambiguity
}

class A {
	template Foo1(int N) if ((N % 2) == 0)    {
		enum Foo1 = "A";
      }
	template Foo1(int N) if ((N % 3) == 0) {
		enum Foo1 = "B";
	}
}
```

Also, you can try without a constraint, it will still complain.

But you are arguing from the point of view of a hypothetical 
semantical equivalence that I don't think it's so clear. Both are 
tools that in some cases can lead to the same result, but there 
are also cases where they don't math.

You could also argue that function overloads are just 
semantically equivalent to a single function with variadic 
arguments. Whether the compiler actually lowers it like that or 
not should be just an implementation detail, and thus simply not 
relevant.

And from a syntactical point of view, it wouldn't make any sense 
if the following "overloads" were treated differently:

```
class A {
     @("int", "odd")
	template Foo1(int N) if (N & 1)    {
         enum Foo1 = "A";
     }
     @("int", "even")
	template Foo1(int N) if (!(N & 1))    {
         enum Foo1 = "B";
     }
     @("string", "+")
	template Foo1(string op) if (op == "+") {
         enum Foo1 = "C";
     }
     @("multi", "string")
	template Foo1(T...) if (allSatisfy!(isSomeString, typeof(T)) && 
T.length > 1) {
         enum Foo1 = "D";
     }
     @("multi", "double")
	template Foo1(T...) if (allSatisfy!(isFloatingPoint, typeof(T)) 
&& T.length > 1) {
         enum Foo1 = "E";
     }
}
```

How would you know which ones are "real" overloads (in your 
meaning)?

A.


More information about the Digitalmars-d-learn mailing list