Jump to page: 1 2
Thread overview
Possible bug
Mar 25, 2013
Sergei Nosov
Mar 25, 2013
bearophile
Mar 25, 2013
Sergei Nosov
Mar 25, 2013
Ali Çehreli
Mar 25, 2013
Ali Çehreli
Mar 26, 2013
Sergei Nosov
Mar 26, 2013
Sergei Nosov
March 25, 2013
Hi!

This code doesn't compile with dmd v2.062 on Linux_x86_64

<pre>
struct test(T)
{
    T *data_;
    this(T *data) {
        data_ = data;
    }
}

void main()
{
    int *cptr = null;
    test!int hello = test(cptr);
}
</pre>

Error:
dmd test.d
test.d(12): Error: struct test.test does not match any function template declaration. Candidates are:
test.d(2):        test.test(T)
test.d(12): Error: struct test.test(T) cannot deduce template function from argument types !()(int*)

Everything's fine if I specify parameters explicitly:
<pre>
test!int hello = test!int(cptr);
</pre>
March 25, 2013
Sergei Nosov:

> Everything's fine if I specify parameters explicitly:
> <pre>
> test!int hello = test!int(cptr);
> </pre>

Some persons have proposed alternative designs, but D is working as currently designed here... Unlike template functions, templated structs don't infer the type.

Bye,
bearophile
March 25, 2013
On Monday, 25 March 2013 at 14:12:17 UTC, bearophile wrote:
> Sergei Nosov:
>
>> Everything's fine if I specify parameters explicitly:
>> <pre>
>> test!int hello = test!int(cptr);
>> </pre>
>
> Some persons have proposed alternative designs, but D is working as currently designed here... Unlike template functions, templated structs don't infer the type.
>
> Bye,
> bearophile

Thx, is there any good rationale?
March 25, 2013
On 03/25/2013 08:11 AM, Sergei Nosov wrote:
> On Monday, 25 March 2013 at 14:12:17 UTC, bearophile wrote:
>> Sergei Nosov:
>>
>>> Everything's fine if I specify parameters explicitly:
>>> <pre>
>>> test!int hello = test!int(cptr);
>>> </pre>
>>
>> Some persons have proposed alternative designs, but D is working as
>> currently designed here... Unlike template functions, templated
>> structs don't infer the type.
>>
>> Bye,
>> bearophile
>
> Thx, is there any good rationale?

This design allows templated constructors:

struct S         // <-- not a template
{
    this(T)(T t) // <-- template
    {
        // ...
    }

    // ...
}

The same in C++...

Ali

March 25, 2013
On Mon, 25 Mar 2013 11:11:40 -0400, Sergei Nosov <sergei.nosov@gmail.com>
wrote:

> On Monday, 25 March 2013 at 14:12:17 UTC, bearophile wrote:
>> Sergei Nosov:
>>
>>> Everything's fine if I specify parameters explicitly:
>>> <pre>
>>> test!int hello = test!int(cptr);
>>> </pre>
>>
>> Some persons have proposed alternative designs, but D is working as currently designed here... Unlike template functions, templated structs don't infer the type.
>>
>> Bye,
>> bearophile
>
> Thx, is there any good rationale?

There really isn't.  I have created an enhancement request that you might
be interested in voting for.

http://d.puremagic.com/issues/show_bug.cgi?id=6082

Note that auto is your friend here to avoid the dual-specification of the template:

auto hello = test!int(cptr);

And you can always create a wrapper function:

test!T mktest(T)(T *ptr) { return test!T(ptr);}

...

auto hello = mktest(cptr); // no explicit instantiation required

-Steve
March 25, 2013
On Mon, 25 Mar 2013 11:31:17 -0400, Ali Çehreli <acehreli@yahoo.com> wrote:

> This design allows templated constructors:
>
> struct S         // <-- not a template
> {
>      this(T)(T t) // <-- template
>      {
>          // ...
>      }
>
>      // ...
> }
>
> The same in C++...

Templated constructors would not be disallowed if you allowed IFTI on templated structs/classes without templated constructors.

When you decompose constructors, they are simply fucntions, and IFTI exists on functions.  The same should be allowed for constructors.

There is almost no difference between this:

template foo(T){
   void foo(T t) {}
}

and this:

struct foo(T){
   this(T t) {}
}

-Steve
March 25, 2013
On 03/25/2013 12:40 PM, Steven Schveighoffer wrote:
> On Mon, 25 Mar 2013 11:31:17 -0400, Ali Çehreli <acehreli@yahoo.com> wrote:
>
>> This design allows templated constructors:
>>
>> struct S // <-- not a template
>> {
>> this(T)(T t) // <-- template
>> {
>> // ...
>> }
>>
>> // ...
>> }
>>
>> The same in C++...
>
> Templated constructors would not be disallowed if you allowed IFTI on
> templated structs/classes without templated constructors.

It would complicate matters: The parameter would be for the constructor if the constructor were a template, for the struct otherwise.

> When you decompose constructors, they are simply fucntions, and IFTI
> exists on functions. The same should be allowed for constructors.

I completely agree and that's my point. :) The template parameter list of the constructor should stay with the constructor.

> There is almost no difference between this:
>
> template foo(T){
> void foo(T t) {}
> }
>
> and this:
>
> struct foo(T){
> this(T t) {}
> }

Actually, the latter is a shorthand for this:

template S(T)
{
    struct S
    {
        T t;

        this(U)(U)
        {}
    }
}

As you see, T comes from the outer template and U stays with the constructor. It allows the following use:

void main()
{
    auto s = S!int(byte.init);
}

>
> -Steve

Ali

March 26, 2013
On Mon, 25 Mar 2013 17:13:58 -0400, Ali Çehreli <acehreli@yahoo.com> wrote:

> On 03/25/2013 12:40 PM, Steven Schveighoffer wrote:
>  > On Mon, 25 Mar 2013 11:31:17 -0400, Ali Çehreli <acehreli@yahoo.com> wrote:
>  >
>  >> This design allows templated constructors:
>  >>
>  >> struct S // <-- not a template
>  >> {
>  >> this(T)(T t) // <-- template
>  >> {
>  >> // ...
>  >> }
>  >>
>  >> // ...
>  >> }
>  >>
>  >> The same in C++...
>  >
>  > Templated constructors would not be disallowed if you allowed IFTI on
>  > templated structs/classes without templated constructors.
>
> It would complicate matters: The parameter would be for the constructor if the constructor were a template, for the struct otherwise.

In cases where the struct is templated and the constructor is not, it would apply to the struct.  In cases where the struct is concrete and the constructor is templated, it would apply to the constructor.  In the case where the struct is templated AND the constructor is templated, it would require the struct to have an explicit instantiation.

This is not complex, nor unintuitive.

>  > When you decompose constructors, they are simply fucntions, and IFTI
>  > exists on functions. The same should be allowed for constructors.
>
> I completely agree and that's my point. :) The template parameter list of the constructor should stay with the constructor.

In the rare cases where the struct and the constructor are templated, it will stay with the constructor.

>  > There is almost no difference between this:
>  >
>  > template foo(T){
>  > void foo(T t) {}
>  > }
>  >
>  > and this:
>  >
>  > struct foo(T){
>  > this(T t) {}
>  > }
>
> Actually, the latter is a shorthand for this:
>
> template S(T)
> {
>      struct S
>      {
>          T t;
>
>          this(U)(U)
>          {}
>      }
> }

No, it is shorthand for this:

template foo(T)
{
   struct foo
   {
      this(T t) {}
   }
}

Note there is only ONE template type.

For your case, the shorthand would be:

struct S(T)
{
   this(U)(U u) {}
}

>
> As you see, T comes from the outer template and U stays with the constructor. It allows the following use:
>
> void main()
> {
>      auto s = S!int(byte.init);
> }

This would be required if both struct and constructor are templated (and rightly so).

-Steve
March 26, 2013
Thank you, guys!

You made the matters clear to me!

It would be an interesting enhancement over C++.

Although, Steven, I didn't quite understand what you're suggesting to use in case of "templated-struct-templated-constructor"

Explicitly specifying struct parameters is ok. Deducing constructor parameters from arguments is also ok. But what if not all of the constructor parameters may be deduced? E.g. one of them is an int?

Would it be a no-no case? or should we merge the lists in one? or should we use two bangs? S!(int, 4)!(byte, 5)(3) ? =)
March 26, 2013
On Tue, 26 Mar 2013 01:28:03 -0400, Sergei Nosov <sergei.nosov@gmail.com> wrote:

> Thank you, guys!
>
> You made the matters clear to me!
>
> It would be an interesting enhancement over C++.
>
> Although, Steven, I didn't quite understand what you're suggesting to use in case of "templated-struct-templated-constructor"
>
> Explicitly specifying struct parameters is ok. Deducing constructor parameters from arguments is also ok. But what if not all of the constructor parameters may be deduced? E.g. one of them is an int?
>
> Would it be a no-no case? or should we merge the lists in one? or should we use two bangs? S!(int, 4)!(byte, 5)(3) ? =)

What you have to do is instantiate the template, then call the constructor:

S!(int, 4).S!(byte, 5)(3)

Note that the way templates work in D, a templated struct is really a shortcut for:

template S(T)
{
   struct S { ... }
}

So when you instantiate it, S!(int)(5) is really shorthand for S!(int).S(5).

Every template is this way.  The shorthand version calls on the "eponymous" member implicitly, that is, the member with the same name as the template.  Currently, this only works if there is exactly one member.

For example, a function template is really:

template foo(T)
{
   void foo(T t) {...}
}

So doing:

foo!(int)(1)

is really the same as:

foo!(int).foo(1)

It's all outlined here: http://dlang.org/template.html

search for Implicit Template Properties

-Steve
« First   ‹ Prev
1 2