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.

Reply via email to