Jump to page: 1 2 3
Thread overview
Template type deduction and specialization
May 20, 2015
Mike Parker
May 20, 2015
jklp
May 20, 2015
Daniel Kozak
May 20, 2015
Namespace
May 20, 2015
Mike Parker
May 20, 2015
Jonathan M Davis
May 20, 2015
Daniel Kozák
May 20, 2015
Daniel Kozak
May 20, 2015
Mike Parker
May 20, 2015
Mike Parker
May 20, 2015
Daniel Kozák
May 20, 2015
Mike Parker
May 21, 2015
Ali Çehreli
May 21, 2015
Daniel Kozák
May 21, 2015
Daniel Kozák
May 21, 2015
Daniel Kozak
May 21, 2015
Daniel Kozák
May 20, 2015
Jonathan M Davis
May 20, 2015
Daniel Kozak
May 20, 2015
Mike Parker
May 21, 2015
Jonathan M Davis
May 20, 2015
I don't understand why this behaves as it does. Given the following two templates:

```
void printVal(T)(T t) {
	writeln(t);
}
void printVal(T : T*)(T* t) {
	writeln(*t);
}
```

I find that I actually have to explicitly instantiate the template with a pointer type to get the specialization.

```
void main() {
	int x = 100;
	printVal(x);
	int* px = &x;
	printVal(px);        // prints the address
        printVal!(int*)(px)  // prints 100
}
```

Intuitively, I would expect the specialization to be deduced without explicit instantiation. Assuming this isn't a bug (I've been unable to turn up anything in Bugzilla), could someone in the know explain the rationale behind this?
May 20, 2015
On Wednesday, 20 May 2015 at 06:31:13 UTC, Mike Parker wrote:
> I don't understand why this behaves as it does. Given the following two templates:
>
> ```
> void printVal(T)(T t) {
> 	writeln(t);
> }
> void printVal(T : T*)(T* t) {
> 	writeln(*t);
> }
> ```
>
> I find that I actually have to explicitly instantiate the template with a pointer type to get the specialization.
>
> ```
> void main() {
> 	int x = 100;
> 	printVal(x);
> 	int* px = &x;
> 	printVal(px);        // prints the address
>         printVal!(int*)(px)  // prints 100
> }
> ```
>
> Intuitively, I would expect the specialization to be deduced without explicit instantiation. Assuming this isn't a bug (I've been unable to turn up anything in Bugzilla), could someone in the know explain the rationale behind this?

---
import std.stdio;

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

void printVal(T: T)(T* t) {
	writeln(*t);
}

void main() {
	int x = 100;
	printVal(x);
	int* px = &x;
	printVal(px);
}
---

here it's selected correctly without explicit instantiation. But honestly i don't know why since the  asterisk is removed from the T it looks quite incorrect.

May 20, 2015
On Wednesday, 20 May 2015 at 06:31:13 UTC, Mike Parker wrote:
> I don't understand why this behaves as it does. Given the following two templates:
>
> ```
> void printVal(T)(T t) {
> 	writeln(t);
> }
> void printVal(T : T*)(T* t) {
> 	writeln(*t);
> }
> ```
>
> I find that I actually have to explicitly instantiate the template with a pointer type to get the specialization.
>
> ```
> void main() {
> 	int x = 100;
> 	printVal(x);
> 	int* px = &x;
> 	printVal(px);        // prints the address
>         printVal!(int*)(px)  // prints 100
> }
> ```
>
> Intuitively, I would expect the specialization to be deduced without explicit instantiation. Assuming this isn't a bug (I've been unable to turn up anything in Bugzilla), could someone in the know explain the rationale behind this?

What about:
----
import std.stdio;

void printVal(T)(T t) {
    static if (is(T : U*, U))
        printVal(*t);
    else
        writeln(t);
}

void main() {
    int x = 100;
    printVal(x);
    int* px = &x;
    printVal(px);
}
----
May 20, 2015
On 5/20/2015 4:36 PM, Namespace wrote:

> What about:
> ----
> import std.stdio;
>
> void printVal(T)(T t) {
>      static if (is(T : U*, U))
>          printVal(*t);
>      else
>          writeln(t);
> }

Thanks, but I'm not looking for alternatives. I'm trying to figure out why it doesn't work as expected.

May 20, 2015
On Wed, 20 May 2015 06:31:11 +0000
Mike Parker via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
wrote:

> I don't understand why this behaves as it does. Given the following two templates:
> 
> ```
> void printVal(T)(T t) {
> 	writeln(t);
> }
> void printVal(T : T*)(T* t) {
> 	writeln(*t);
> }
> ```
> 
> I find that I actually have to explicitly instantiate the template with a pointer type to get the specialization.
> 
> ```
> void main() {
> 	int x = 100;
> 	printVal(x);
> 	int* px = &x;
> 	printVal(px);        // prints the address
>          printVal!(int*)(px)  // prints 100
> }
> ```
> 
> Intuitively, I would expect the specialization to be deduced without explicit instantiation. Assuming this isn't a bug (I've been unable to turn up anything in Bugzilla), could someone in the know explain the rationale behind this?

Because it cannot deduce type T:

try this:

void printVal(T : T*)(T* t) {
    writeln(*t);
}

void main() {
 	int x = 100;
 	int* px = &x;
 	printVal(px);
}

It will print error.

My advise is not to use T:T* or T:T[] it works only when explicitly instantiate. Is better use T:M*,M or T:M[], M because it works automaticly and you have both types available.

import std.stdio;

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

void printVal(T:M*,M)(T t) {
    writeln(*t);
}

void main() {
    int x = 100;
    printVal(x);
    int* px = &x;
    printVal(px);        // prints the 100
}
May 20, 2015
On Wednesday, 20 May 2015 at 09:24:28 UTC, Daniel Kozák wrote:
>
> On Wed, 20 May 2015 06:31:11 +0000
> Mike Parker via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
> wrote:
>
>> I don't understand why this behaves as it does. Given the following two templates:
>> 
>> ```
>> void printVal(T)(T t) {
>> 	writeln(t);
>> }
>> void printVal(T : T*)(T* t) {
>> 	writeln(*t);
>> }
>> ```
>> 
>> I find that I actually have to explicitly instantiate the template with a pointer type to get the specialization.
>> 
>> ```
>> void main() {
>> 	int x = 100;
>> 	printVal(x);
>> 	int* px = &x;
>> 	printVal(px);        // prints the address
>>          printVal!(int*)(px)  // prints 100
>> }
>> ```
>> 
>> Intuitively, I would expect the specialization to be deduced without explicit instantiation. Assuming this isn't a bug (I've been unable to turn up anything in Bugzilla), could someone in the know explain the rationale behind this?
>
> Because it cannot deduce type T:
>
> try this:
>
> void printVal(T : T*)(T* t) {
>     writeln(*t);
> }
>
> void main() {
>  	int x = 100;
>  	int* px = &x;
>  	printVal(px);
> }
>
> It will print error.
>
> My advise is not to use T:T* or T:T[] it works only when explicitly
> instantiate. Is better use T:M*,M or T:M[], M because it works
> automaticly and you have both types available.
>
> import std.stdio;
>
> void printVal(T)(T t) {
>     writeln(t);
> }
>
> void printVal(T:M*,M)(T t) {
>     writeln(*t);
> }
>
> void main() {
>     int x = 100;
>     printVal(x);
>     int* px = &x;
>     printVal(px);        // prints the 100
> }

DOCS: http://dlang.org/template.html#function-templates
says: Function template type parameters that are to be implicitly deduced may not have specializations:
May 20, 2015
On Wednesday, May 20, 2015 06:31:11 Mike Parker via Digitalmars-d-learn wrote:
> I don't understand why this behaves as it does. Given the following two templates:
>
> ```
> void printVal(T)(T t) {
>   writeln(t);
> }
> void printVal(T : T*)(T* t) {
>   writeln(*t);
> }
> ```
>
> I find that I actually have to explicitly instantiate the template with a pointer type to get the specialization.
>
> ```
> void main() {
>   int x = 100;
>   printVal(x);
>   int* px = &x;
>   printVal(px);        // prints the address
>          printVal!(int*)(px)  // prints 100
> }
> ```
>
> Intuitively, I would expect the specialization to be deduced without explicit instantiation. Assuming this isn't a bug (I've been unable to turn up anything in Bugzilla), could someone in the know explain the rationale behind this?

Well, if

printVal!(int*)(px);

prints 100, then that's a bug. It should print the address. In fact, it should be _impossible_ for the second overload of printVal to ever be instantiated. Think about it. What does T : T* mean? It means that T is implicitly convertible to T*. And when is a type ever implicitly convertible to a pointer to itself?

int x = 100;
int y = &x;

isn't going to compile, so neither should that second overload ever end up being used. Use std.traits.isPointer if you want to test for whether a type is a pointer or not.

I'm using a fairly recent version of dmd master, and it prints out the address for px in both cases when I compile your code. So, if it's printing out 100 for you on the second call, it would appear to be a bug that has been fixed at some point since 2.067 (or whatever version you're using) was released.

- Jonathan M Davis

May 20, 2015
On Wednesday, May 20, 2015 07:36:21 Namespace via Digitalmars-d-learn wrote:
> What about:
> ----
> import std.stdio;
>
> void printVal(T)(T t) {
>      static if (is(T : U*, U))
>          printVal(*t);
>      else
>          writeln(t);
> }
>
> void main() {
>      int x = 100;
>      printVal(x);
>      int* px = &x;
>      printVal(px);
> }
> ----

That mostly works, but you it runs the classic risk of running into problems with alias this (which is why checking for implicit conversions in static if or template constraints is so incredibly dangerous if you're not _very_ careful). std.traits defines isPointer as follows:

enum bool isPointer(T) = is(T == U*, U) && !isAggregateType!T;

which avoids the alias this problem. Regardless, it's more idiomatic to just use isPointer.

- Jonathan M Davis

May 20, 2015
On Wednesday, 20 May 2015 at 07:27:53 UTC, jklp wrote:
>
> ---
> import std.stdio;
>
> void printVal(T)(T t) {
> 	writeln(t);
> }
>
> void printVal(T: T)(T* t) {
> 	writeln(*t);
> }
>
> void main() {
> 	int x = 100;
> 	printVal(x);
> 	int* px = &x;
> 	printVal(px);
> }
> ---
>
> here it's selected correctly without explicit instantiation. But honestly i don't know why since the  asterisk is removed from the T it looks quite incorrect.

No it is correct it is same as:
void printVal(T: int)(T* t) {
    writeln(*t);
}
May 20, 2015
On Wednesday, 20 May 2015 at 09:35:48 UTC, Jonathan M Davis wrote:
>
> Well, if
>
> printVal!(int*)(px);
>
> prints 100, then that's a bug. It should print the address. In fact, it
> should be _impossible_ for the second overload of printVal to ever be
> instantiated

IMHO thats not true, it should print 100. This is what spec say.

void printVal(T : T*)(T* t) {
    writeln(*t);
}

T is deduce to be int so we have

void printVal(int* t) {
    writeln(*t);
}

which will print value not address
« First   ‹ Prev
1 2 3