www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Strange Error using parameterized opAssign for a struct

reply d coder <dlang.coder gmail.com> writes:
Greetings All

I have a Struct (see minimized code below) which is failing for a simple
assignment. I am using DMD 2.053, and am getting an error:

 implicit.d(14): Error: cannot implicitly convert expression (foo1) of type
Foo!(4) to Foo!(NN) Am I doing something wrong, or have I hit a DMD bug? Kindly note that this happens only when I parameterize the struct using an Integral parameter, and works file when using string as parameter (as with struct Bar in the code). Regards - Puneet // File implicit.d struct Foo (size_t N) { void opAssign (size_t NN)(Foo!(NN) f) {/*do nothing*/} } struct Bar (string S) { void opAssign (string SS)(Bar!(SS) f) {/*do nothing*/} } void main() { Bar!"BAR1" bar1; Bar!"BAR2" bar2; bar2 = bar1; // this compiles fine Foo!4 foo1; Foo!4 foo2; foo2 = foo1; // compilation error }
Jul 04 2011
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 04 Jul 2011 05:58:45 -0400, d coder <dlang.coder gmail.com> wrote:

 Greetings All

 I have a Struct (see minimized code below) which is failing for a simple  
 assignment. I am using DMD 2.053, and am getting an error:

 implicit.d(14): Error: cannot implicitly convert expression (foo1) of  
 type Foo!(4) to Foo!(NN)
Am I doing something wrong, or have I hit a DMD bug? Kindly note that this happens only when I parameterize the struct using an Integral parameter, and works file when using string as parameter (as with struct Bar in the code). Regards - Puneet
Yes and No. DMD has trouble deducing the correct template parameters for implicit function template instantiating when you make the template parameter the input to another template. The solution is to match a general type T and constrain it. (DMD can do these more complex matches inside an is expression, etc. So you can rewrite your code as: // File implicit.d struct Foo (size_t N) { void opAssign (T:Foo!NN,size_t NN)(T f) {/*do nothing*/} } struct Bar (string S) { void opAssign (string SS)(Bar!(SS) f) {/*do nothing*/} } void main() { Bar!"BAR1" bar1; Bar!"BAR2" bar2; bar2 = bar1; // this compiles fine Foo!4 foo1; Foo!4 foo2; foo2 = foo1; // Now compiles } Also, if you want to instantiate a Foo!NN, IIRC there's similar bug where the type becomes Foo!NN and not Foo!4. The solution is to use Foo!(NN+0) (or T) instead.
Jul 04 2011
next sibling parent d coder <dlang.coder gmail.com> writes:
Thanks Robert

Meanwhile, I also found that my code works it I change parameter type to int
instead of size_t. Looks like DMD fails because of some issue with implicit
conversions (or lack of it) between integral types.

Anyway the solution you provided is more elegant and I will adopt that.

Regards
- Puneet
Jul 04 2011
prev sibling next sibling parent d coder <dlang.coder gmail.com> writes:
Greetings Robert/All

Robert suggested that I put my opAssign method as:

void opAssign (T:Foo!NN,size_t NN)(T f) { }

That works. But I want to find out if it is possible to write the opAssign
template method with a conditional in the following form. This will help me
optimize code better. Kindly suggest what would come in place of .......
below.

void opAssign (T)(T f) if(is(T .......)) { }

Regards
- Puneet
Jul 04 2011
prev sibling next sibling parent d coder <dlang.coder gmail.com> writes:
 Robert suggested that I put my opAssign method as:

 void opAssign (T:Foo!NN,size_t NN)(T f) { }

 That works. But I want to find out if it is possible to write the opAssign
 template method with a conditional in the following form. This will help me
 optimize code better. Kindly suggest what would come in place of .......
 below.

 void opAssign (T)(T f) if(is(T .......)) { }
void opAssign (T)(T f) if(is(T L : Foo!(NN,MM), int NN, int MM)) { } I found that the above declaration compiles. But again it compiles with int as parameter type. Fails for size_t. Any other idea? Regards - Puneet
Jul 05 2011
prev sibling parent d coder <dlang.coder gmail.com> writes:
Hello Robert

As I try adding more code, I get into more and more issues with integral
parameters. See the following code:

Regards
- Puneet

// File implicit.d
alias int R;
// alias size_t R;
struct Foo (R N) {
  version(v1) {void opAssign (R NN)(Foo!NN f) {/*do nothing*/}}
  version(v2) {void opAssign (T:Foo!NN, R NN)(T f) {/*do nothing*/}}
   property Foo!(I) range(R I)() {return Foo!(I)();}
}
void main() {
  Foo!4 foo1;
  Foo!7 foo2;
  foo2 = foo1; // compiles with both v2 and v1/(only when R is aliased to
int)
  foo2 = foo1.range!4; // compiles with v1/int and v2/int -- does not
compile with R alias to size_t
  foo2 = foo1.range!2; // compiles only with v1/int -- does not compile with
v2 at all
}
Jul 05 2011