www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Templates array detection

reply "Cube" <sq ua.re> writes:
Hi,

I'm having a problem getting templates to work correctly.
I want to handle arrays differently, but when I try to compile 
the following example code it says it matches more than 1 
template. What is the correct way to do this?


--
void main()
{
     foo(1);
     foo([1,1]);
}

void foo(T)(T t)
{
     writeln(t);
}

void foo(T)(T[] t)
{
     for(int i = 0; i < t.length; i++)
         writeln(t[i]);
}
--
Dec 12 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Cube:

 I'm having a problem getting templates to work correctly.
 I want to handle arrays differently, but when I try to compile 
 the following example code it says it matches more than 1 
 template. What is the correct way to do this?


 --
 void main()
 {
     foo(1);
     foo([1,1]);
 }

 void foo(T)(T t)
 {
     writeln(t);
 }

 void foo(T)(T[] t)
 {
     for(int i = 0; i < t.length; i++)
         writeln(t[i]);
 }
 --
In general D templates refuse ambiguity. So to fix your situation you have to state that the T in your first foo overload is not an array: import std.stdio, std.traits; void main() { foo(1); foo([1, 1]); } void foo(T)(T t) if (!isArray!T) { writeln(t); } void foo(T)(T[] t) { foreach (ti; t) writeln(ti); } Bye, bearophile
Dec 12 2012
next sibling parent reply "Cube" <sq ua.re> writes:
On Wednesday, 12 December 2012 at 12:34:34 UTC, bearophile wrote:
 Cube:

 I'm having a problem getting templates to work correctly.
 I want to handle arrays differently, but when I try to compile 
 the following example code it says it matches more than 1 
 template. What is the correct way to do this?


 --
 void main()
 {
    foo(1);
    foo([1,1]);
 }

 void foo(T)(T t)
 {
    writeln(t);
 }

 void foo(T)(T[] t)
 {
    for(int i = 0; i < t.length; i++)
        writeln(t[i]);
 }
 --
In general D templates refuse ambiguity. So to fix your situation you have to state that the T in your first foo overload is not an array: import std.stdio, std.traits; void main() { foo(1); foo([1, 1]); } void foo(T)(T t) if (!isArray!T) { writeln(t); } void foo(T)(T[] t) { foreach (ti; t) writeln(ti); } Bye, bearophile
Hi, I eventually modified my code to: -- void main() { foo(1); foo([1,1]); } void foo(T)(T t) { bar!(T)(t); } void bar(T)(T t) { writeln(t+1); } void bar(T: T[])(T[] t) { for(int i = 0; i < t.length; i++) writeln(t[i]); } -- Essentially I added a helper function that added !(T). What, if any, is the benefit of either approach? And a similar issue, what if I have a struct: -- struct Data(T) { int elem = 3; } void main() { foo(1); foo([1,1]); foo(new Data!(int)); foo(new Data!(float)); } void foo(T)(T t) { bar!(T)(t); } void bar(T)(T t) { writeln(t+1); } void bar(T: T[])(T[] t) { for(int i = 0; i < t.length; i++) writeln(t[i]); } -- And I want to add this to the rest of the program. Where/how can I direct the Data's to separate functions? Thanks :)
Dec 12 2012
parent reply "Cube" <sq ua.re> writes:
Better example code for my other problem. How can I make the 3rd 
foo work on  Datas?

--
struct Data(T)
{
	T elem;
}

void main()
{
	foo(1);
	foo([1,1]);

	auto tmp1 = new Data!(int);
	tmp1.elem = 3;
	foo(tmp1);

	auto tmp2 = new Data!(string);
	tmp2.elem = "hello";
	foo(tmp2);
}

void foo(T)(T t) if(!isArray!T)
{
	writeln(t + 1);
}

void foo(T)(T t) if(isArray!T)
{
	for(int i = 0; i < t.length; i++)
		writeln(t[i]);
}

void foo(T)(T t) if(is(T == Data)) // ?
{
	if(is(T == Data!int))
		writeln(t.elem + 1);
	else if(is(T == Data!string))
		writeln(t.elem);
}
--
Dec 12 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/12/2012 06:49 AM, Cube wrote:
 Better example code for my other problem. How can I make the 3rd foo
 work on Datas?

 --
 struct Data(T)
 {
 T elem;
 }
Data is a struct template, not a type (until instantiated).
 void foo(T)(T t) if(is(T == Data)) // ?
This works: void foo(T)(T t) if(is(T == Data!T))
 {
 if(is(T == Data!int))
 writeln(t.elem + 1);
 else if(is(T == Data!string))
 writeln(t.elem);
 }
 --
Ali
Dec 12 2012
next sibling parent reply "Cube" <sq ua.re> writes:
On Wednesday, 12 December 2012 at 15:21:16 UTC, Ali Çehreli wrote:
 On 12/12/2012 06:49 AM, Cube wrote:
 Better example code for my other problem. How can I make the
3rd foo
 work on Datas?

 --
 struct Data(T)
 {
 T elem;
 }
Data is a struct template, not a type (until instantiated).
 void foo(T)(T t) if(is(T == Data)) // ?
This works: void foo(T)(T t) if(is(T == Data!T))
It doesn't seem to work for me, it uses the first foo. And I can't see how it would work, actually. If T is a Data!float, then wouldn't is(T == Data!T) be equal to is(Data!float == Data!Data!float) ?
 Ali
Dec 12 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/12/2012 07:37 AM, Cube wrote:
 On Wednesday, 12 December 2012 at 15:21:16 UTC, Ali Çehreli wrote:
 On 12/12/2012 06:49 AM, Cube wrote:
 Better example code for my other problem. How can I make the
3rd foo
 work on Datas?

 --
 struct Data(T)
 {
 T elem;
 }
Data is a struct template, not a type (until instantiated).
 void foo(T)(T t) if(is(T == Data)) // ?
This works: void foo(T)(T t) if(is(T == Data!T))
It doesn't seem to work for me, it uses the first foo. And I can't see how it would work, actually. If T is a Data!float, then wouldn't is(T == Data!T) be equal to is(Data!float == Data!Data!float) ?
I have to deal with the magical 'is expression' again! :p First, also notice that you ar not passing Data!T but a pointer to Data!T. This program works: import std.stdio; import std.traits; struct Data(T) { T elem; } void main() { foo(1); foo([1,1]); auto tmp1 = new Data!(int); tmp1.elem = 3; foo(tmp1); auto tmp2 = new Data!(string); tmp2.elem = "hello"; foo(tmp2); } void foo(T)(T t) if(!isArray!T && !is(T ThisIsNeededButUnusable : Data!U*, U)) { writeln(t + 1); } void foo(T)(T t) if(isArray!T) { for(int i = 0; i < t.length; i++) writeln(t[i]); } void foo(T)(T t) if (is(T ThisIsNeededButUnusable : Data!U*, U)) { writeln("desired"); // Note that both of the 'if's are replaced with 'static if's. // Also, both are 'pointers' in the conditionals. static if(is(T == Data!int*)) writeln(t.elem + 1); else static if(is(T == Data!string*)) writeln(t.elem); } I think ThisIsNeededButUnusable above is a compiler bug. It has a use when the body of the 'is' is used inside template parameter lists but not in a template constraint. It is still needed to satisfy the syntax... (?) Ali
Dec 12 2012
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

 This works:

 void foo(T)(T t) if(is(T == Data!T))
Try: void foo(T)(Data!T t) { Bye, bearophile
Dec 12 2012
prev sibling parent reply "ixid" <nuaccount gmail.com> writes:
On Wednesday, 12 December 2012 at 12:34:34 UTC, bearophile wrote:
 Cube:

 I'm having a problem getting templates to work correctly.
 I want to handle arrays differently, but when I try to compile 
 the following example code it says it matches more than 1 
 template. What is the correct way to do this?


 --
 void main()
 {
    foo(1);
    foo([1,1]);
 }

 void foo(T)(T t)
 {
    writeln(t);
 }

 void foo(T)(T[] t)
 {
    for(int i = 0; i < t.length; i++)
        writeln(t[i]);
 }
 --
In general D templates refuse ambiguity. So to fix your situation you have to state that the T in your first foo overload is not an array: import std.stdio, std.traits; void main() { foo(1); foo([1, 1]); } void foo(T)(T t) if (!isArray!T) { writeln(t); } void foo(T)(T[] t) { foreach (ti; t) writeln(ti); } Bye, bearophile
It's a pity it doesn't see T[] as the best fit and go with it on that basis.
Dec 12 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
ixid:

 It's a pity it doesn't see T[] as the best fit and go with it 
 on that basis.
It's not a pity, it's a good design. "Best fit" makes language&compiler complex, less predictable for the programmer, etc. Bye, bearophile
Dec 12 2012
parent reply "ixid" <nuaccount gmail.com> writes:
On Wednesday, 12 December 2012 at 14:21:22 UTC, bearophile wrote:
 ixid:

 It's a pity it doesn't see T[] as the best fit and go with it 
 on that basis.
It's not a pity, it's a good design. "Best fit" makes language&compiler complex, less predictable for the programmer, etc. Bye, bearophile
It seems very similar to a function overload to me. Why is picking T[] in preference to T different to picking uint over ulong for an overloaded function used on a uint?
Dec 12 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
ixid:

 It seems very similar to a function overload to me. Why is 
 picking T[] in preference to T different to picking uint over 
 ulong for an overloaded function used on a uint?
The name T can refer to any type, including a U[], while built-in types like uint are atomic, they can't refer to a composed type. And there is difference between a built-in type where both the programmer and the compiler know about, and generic user defined types. And template types are used in an exact way, unlike function overloading they don't perform implicit type conversions. Bye, bearophile
Dec 12 2012