Template parameter deduction for constructors?

Steven Schveighoffer schveiguy at yahoo.com
Mon Apr 15 08:12:26 PDT 2013


On Sun, 14 Apr 2013 10:29:11 -0400, Peter Alexander  
<peter.alexander.au at gmail.com> wrote:

> On Saturday, 13 April 2013 at 15:52:01 UTC, David Nadlinger wrote:
>> On Saturday, 13 April 2013 at 08:40:15 UTC, Peter Alexander wrote:
>>> This just seems like a bandaid solution to the problem. If it works in  
>>> this case then beginners will think it works in every case, and will  
>>> be even more confused when it stops working.
>>
>> When would it stop working? You might want to add any such example to  
>> http://d.puremagic.com/issues/show_bug.cgi?id=6082.
>
> Something like this:
>
> struct Foo(T)
> {
>      static if (is(T == int))
>          this(string x) {}
>      else
>          this(T x) {}
> }
>
> T is ambiguous for Foo("bar")

template Foo(T)
{
    static if(is(T == int))
        Foo(string x) {}
    else
        Foo(T x) {}
}

This is the equivalent function.  It correctly requires explicit  
instantiation, and cannot involve IFTI.

>
>
> Also this:
>
> struct Foo(T)
> {
>      this(T x) {}
>      this(int x) {}
> }
>
> Calls to Foo(x) are ambiguous when is(typeof(x) : int).

Foo!int is not ambiguous, it's illegal.

Technically, a valid implementation would be:

struct Foo(T)
{
    this(T x) {}
    static if(is(T != int))
       this(int x) {}
}

Which I think should instantiate just fine, but I don't know.

> Allowing deduction in this case would be frustrating. Imagine having a  
> struct where this worked, and then you wanted to add a new constructor,  
> or maybe just modify the constructor for one instantiation. You would  
> then have to change all calls to explicitly specify parameters.

This is due to issues with the compiler.  It currently requires a specific  
form to use IFTI, this would necessarily need to change.  If the  
constructor is ambiguous or did not involve the template type (such as  
your int x argument above), then you would have to explicitly instantiate,  
necessarily.

But you should be allowed to do something like this:

struct S(T)
{
    this(T t) {}
    this(T t, string s) {}
}

>> The complexity is already there, in the form of (free) ITFI functions.
>
> Unfortunately you are right because of the eponymous template hack.  
> Without it, normal functions are non-complex.
>
> void foo(T)(T x) {}
> void foo(string x) {}
>
> Here, foo("bar") is unambiguously the second call. (D compilers don't  
> allow template/non-template overloads at the moment due to a bug, but  
> this should work).

This is not the same as a template struct with multiple constructors.  It  
is like having two structs, one which is templated, one which is not.   
Given that the above currently doesn't work, I don't know what should  
happen with multiple structs, but I think it should be consistent with  
correct overloaded function behavior.

>
> Unfortunately the eponymous hack falls down quite easily. For example,  
> IFTI on this function fails:
>
> template foo(T)
> {
>      static if (true)
>          void foo(T)(T x) {}
> }
>
> So it is just as fragile as this proposal.

That is an issue with IFTI, not the proposal.  Any enhancements with IFTI  
should translate to this as well.

I think your concerns are a bit exaggerated.  This is something that is  
more than annoying for the cases where there is one constructor, and by  
default falls back on current behavior.  We are adding to the current  
behavior, not breaking it, any perceived incorrect behavior is not any  
more confusing that the current IFTI rules.

-Steve


More information about the Digitalmars-d mailing list