www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implicit Conversions in Struct Construction

reply "Michael" <pongad gmail.com> writes:
Hello,
   I have been playing around with templated range. I am not quite 
sure why the following code does not work:

template isIntLike(T) {
	enum isIntLike = is(typeof({
		T t = 0;
		t = t+t;
		// More if needed
	}));
}

auto fib(T = int)() if (isIntLike!T) {
	struct Fib {
		T a, b;
		
		T front() {return b;}
		bool empty() {return false;}
		
		void popFront() {
			T c = a+b;
			a = b;
			b = c;
		}
	}
	return Fib(0, 1);
}

This code does not work if I call fib!BigInt(). The compiler 
complains that 0 cannot be implicitly converted into a BigInt. It 
is right of course, but BigInt has a constructor accepting a 
long, so shouldn't this work anyway? What is the correct way to 
write this function?

Thank you all for your time,
Michael
Oct 18 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, October 19, 2012 05:44:10 Michael wrote:
 Hello,
    I have been playing around with templated range. I am not quite
 sure why the following code does not work:
 
 template isIntLike(T) {
 	enum isIntLike = is(typeof({
 		T t = 0;
 		t = t+t;
 		// More if needed
 	}));
 }
 
 auto fib(T = int)() if (isIntLike!T) {
 	struct Fib {
 		T a, b;
 
 		T front() {return b;}
 		bool empty() {return false;}
 
 		void popFront() {
 			T c = a+b;
 			a = b;
 			b = c;
 		}
 	}
 	return Fib(0, 1);
 }
 
 This code does not work if I call fib!BigInt(). The compiler
 complains that 0 cannot be implicitly converted into a BigInt. It
 is right of course, but BigInt has a constructor accepting a
 long, so shouldn't this work anyway? What is the correct way to
 write this function?

Constructors aren't implicitly called in D like they are in C++. If you have a function which takes a BigInt, it won't accept anything except a BigInt and something which implicitly converts to a BigInt (which would mean that the type had an alias this which converted it to BigInt). So, Fib(0, 1) will never work for Fib!BigInt. It would require Fib(BigInt(0), BigInt(1)), which you obviously can't do in generic code. However, you can use std.conv.to to do the conversion, so it becomes Fib(to!T(0), to!T(1)), and that should work (to will call the constructor if the constructor accepts the type that you're giving it). But if you do that, you should probably adjust isIntLike to also test that to!T(0) works. - Jonathan M Davis
Oct 18 2012
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 10/18/2012 08:44 PM, Michael wrote:

 auto fib(T = int)() if (isIntLike!T) {
 struct Fib {
 T a, b;

// ...
 return Fib(0, 1);
 }

 This code does not work if I call fib!BigInt(). The compiler complains
 that 0 cannot be implicitly converted into a BigInt. It is right of
 course, but BigInt has a constructor accepting a long, so shouldn't this
 work anyway? What is the correct way to write this function?

Explicit conversion works: return Fib(T(0), T(1)); Ali
Oct 18 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, October 18, 2012 20:55:12 Ali =C3=87ehreli wrote:
 Explicit conversion works:
=20
      return Fib(T(0), T(1));

Except that that won't work for int or other built-in types, because th= ey lack=20 constructors. What you need is std.conv.to. - Jonathan M Davis
Oct 18 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 Except that that won't work for int or other built-in types, 
 because they lack constructors.

Isn't it possible to modify D and add constructors to built-in types? int(10) Bye, bearophile
Oct 19 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, October 19, 2012 10:59:07 bearophile wrote:
 Jonathan M Davis:
 Except that that won't work for int or other built-in types,
 because they lack constructors.

Isn't it possible to modify D and add constructors to built-in types? int(10)

Of course, it would be possible. Whether Walter would agree to though, I have no idea. C++ allows it only because it allows you to use the cast operator in reverse - i.e. int(10) is identical to (int)10 - though it wouldn't need it in the OP's example, because it would do the implicit conversion. What I'd like to see even more is the ability to do auto i = new int(10); which would be particularly useful with immutable, since right now, it's impossible to create an immutable pointer to int with a value of anything other than 0 without casting. - Jonathan M Davis
Oct 19 2012
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 19 October 2012 at 09:36:14 UTC, Jonathan M Davis 
wrote:
 On Friday, October 19, 2012 10:59:07 bearophile wrote:
 Jonathan M Davis:
 Except that that won't work for int or other built-in types,
 because they lack constructors.

Isn't it possible to modify D and add constructors to built-in types? int(10)

Of course, it would be possible. Whether Walter would agree to though, I have no idea. C++ allows it only because it allows you to use the cast operator in reverse - i.e. int(10) is identical to (int)10 - though it wouldn't need it in the OP's example, because it would do the implicit conversion. What I'd like to see even more is the ability to do auto i = new int(10); which would be particularly useful with immutable, since right now, it's impossible to create an immutable pointer to int with a value of anything other than 0 without casting. - Jonathan M Davis

You can use the array.ptr "trick" (or exploit): void main() { immutable int a = 5; immutable(int)* p1 = [a].ptr; immutable(int*) p2 = [a].ptr; } That said, it is ugly as sin, and "new int(5)" should definitely supported. Same thing with structs actually, which can be "agglomerate constructed", or "default copy constructed" : If you can write "auto a = T(x);" you should be able to write "auto p = new T(x)";
Oct 19 2012