www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Possible bug

reply "Sergei Nosov" <sergei.nosov gmail.com> writes:
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>
Mar 25 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Mar 25 2013
parent reply "Sergei Nosov" <sergei.nosov gmail.com> writes:
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?
Mar 25 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Mar 25 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 25 Mar 2013 11:31:17 -0400, Ali =C3=87ehreli <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
Mar 25 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Mar 25 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 25 Mar 2013 17:13:58 -0400, Ali =C3=87ehreli <acehreli yahoo.com=
 wrote:
 On 03/25/2013 12:40 PM, Steven Schveighoffer wrote:
  > On Mon, 25 Mar 2013 11:31:17 -0400, Ali =C3=87ehreli <acehreli yaho=
o.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 constructo=
r =
 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 th= e = constructor is templated, it would apply to the constructor. In the cas= e = 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 IFT=
I
  > 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 =3D S!int(byte.init);
 }
This would be required if both struct and constructor are templated (and= = rightly so). -Steve
Mar 25 2013
parent reply "Sergei Nosov" <sergei.nosov gmail.com> writes:
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) ? =)
Mar 25 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Mar 25 2013
parent "Sergei Nosov" <sergei.nosov gmail.com> writes:
On Tuesday, 26 March 2013 at 05:40:00 UTC, Steven Schveighoffer 
wrote:
 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
Thx a lot!
Mar 26 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Mar 25 2013