Thread overview
Unusual template specialisation behavior
Feb 08, 2008
Matthias Walter
Feb 08, 2008
Christopher Wright
Feb 08, 2008
Sergey Gromov
Feb 08, 2008
Matthias Walter
Feb 08, 2008
Matthias Walter
Feb 08, 2008
Christopher Wright
February 08, 2008
Hello guys,

Here's a (minimal) code snippet for my problem:

| struct Expression (R, E) { }
|
| struct ResolveReference (T)
| {
|     alias T reference_type;
| }
|
| struct ResolveReference (T : Expression !(R, E))
| {
|     alias T* reference_type;
| }
|
| void printRefType (T) ()
| {
|     Stdout (ResolveReference !(Expression !(T, T)).reference_type.stringof).newline;
| }
|
int main (char[][] args)
| {
|     printRefType !(uint);
|     printRefType !(int);
|     printRefType !(long);
|     printRefType !(char);
|     printRefType !(float);
|
|     return 0;
| }

The output is:

| Expression!(uint,uint)
| Expression!(int,int) *
| Expression!(long,long)
| Expression!(char,char)
| Expression!(float,float)

If my understanding of template specialisation is correct, only the second call instanciates the template "ResolveReference (T : Expression !(R, E))" and the other ones choose "ResolveReference (T)". Why does this happen only for ints?

My intended behavior would be, that ResolveReference.reference_type is T*, if T is an Expression and T if not. Thus, I expected, that this code returns

| Expression!(uint,uint) *
| Expression!(int,int) *
| Expression!(long,long) *
| Expression!(char,char) *
| Expression!(float,float) *

btw, this is tested on Linux, Tango rev 3152, Digital Mars D Compiler v1.021. Hopefully, I did not miss a bug-fix.

best regards
Matthias Walter
February 08, 2008
Matthias Walter wrote:
> Hello guys,
> 
> Here's a (minimal) code snippet for my problem:
> 
> | struct Expression (R, E) { }
> | | struct ResolveReference (T)
> | {
> |     alias T reference_type;
> | }
> | | struct ResolveReference (T : Expression !(R, E))

The compiler should have caught this, I think. You have R and E, but they aren't defined. They default to int (which is why you saw that behavior), but not being defined, they should be a compile-time error.

The proper way to do this, unfortunately, involves static if rather than overloading. At least if you want your users to supply a single argument in all cases.
February 08, 2008
Christopher Wright <dhasenan@gmail.com> wrote:
> Matthias Walter wrote:
> > Hello guys,
> > 
> > Here's a (minimal) code snippet for my problem:
> > 
> > | struct Expression (R, E) { }
> > |
> > | struct ResolveReference (T)
> > | {
> > |     alias T reference_type;
> > | }
> > |
> > | struct ResolveReference (T : Expression !(R, E))
> 
> The compiler should have caught this, I think. You have R and E, but they aren't defined. They default to int (which is why you saw that behavior), but not being defined, they should be a compile-time error.
> 
> The proper way to do this, unfortunately, involves static if rather than overloading. At least if you want your users to supply a single argument in all cases.

struct ResolveReference (T : Expression !(R, E), R, E)
{
    alias T* reference_type;
}

works just fine:

void main (char[][] args)
{
    printRefType !(uint);
    printRefType !(int);
    printRefType !(long);
    printRefType !(char);
    printRefType !(float);

    Stdout (ResolveReference !(uint).reference_type.stringof).newline;
}

Expression!(uint,uint)*
Expression!(int,int)*
Expression!(long,long)*
Expression!(char,char)*
Expression!(float,float)*
uint

-- 
SnakE
February 08, 2008
Sergey Gromov Wrote:

> Christopher Wright <dhasenan@gmail.com> wrote:
> > Matthias Walter wrote:
> > > Hello guys,
> > > 
> > > Here's a (minimal) code snippet for my problem:
> > > 
> > > | struct Expression (R, E) { }
> > > |
> > > | struct ResolveReference (T)
> > > | {
> > > |     alias T reference_type;
> > > | }
> > > |
> > > | struct ResolveReference (T : Expression !(R, E))
> > 
> > The compiler should have caught this, I think. You have R and E, but they aren't defined. They default to int (which is why you saw that behavior), but not being defined, they should be a compile-time error.
> > 
> > The proper way to do this, unfortunately, involves static if rather than overloading. At least if you want your users to supply a single argument in all cases.
> 
> struct ResolveReference (T : Expression !(R, E), R, E)
> {
>     alias T* reference_type;
> }
> 
> works just fine:
> 
> void main (char[][] args)
> {
>     printRefType !(uint);
>     printRefType !(int);
>     printRefType !(long);
>     printRefType !(char);
>     printRefType !(float);
> 
>     Stdout (ResolveReference !(uint).reference_type.stringof).newline;
> }
> 
> Expression!(uint,uint)*
> Expression!(int,int)*
> Expression!(long,long)*
> Expression!(char,char)*
> Expression!(float,float)*
> uint
> 
> -- 
> SnakE

Thank you both! I guess, this works, because when passing an Expression !(R, E), the 2nd and 3rd specialisation parameters R and E are deduced and everything works fine, right? Thanks for your help!

best regards
Matthias Walter
February 08, 2008
Christopher Wright Wrote:

> Matthias Walter wrote:
> > Hello guys,
> > 
> > Here's a (minimal) code snippet for my problem:
> > 
> > | struct Expression (R, E) { }
> > |
> > | struct ResolveReference (T)
> > | {
> > |     alias T reference_type;
> > | }
> > |
> > | struct ResolveReference (T : Expression !(R, E))
> 
> The compiler should have caught this, I think. You have R and E, but they aren't defined. They default to int (which is why you saw that behavior), but not being defined, they should be a compile-time error.
> 
> The proper way to do this, unfortunately, involves static if rather than overloading. At least if you want your users to supply a single argument in all cases.

Thanks for that hint. How would such a static if look like?

I currently have

| static if (is (T == struct)).

This works for distinguishing native datatypes like int from my Expression-Templates.
But is there a native way to statically check, whether T is some specialisation like
 "T == Expression !(R, E)" (for all R, E).

best regards
Matthias Walter
February 08, 2008
Matthias Walter wrote:
> Christopher Wright Wrote:
> 
>> Matthias Walter wrote:
>>> Hello guys,
>>>
>>> Here's a (minimal) code snippet for my problem:
>>>
>>> | struct Expression (R, E) { }
>>> | | struct ResolveReference (T)
>>> | {
>>> |     alias T reference_type;
>>> | }
>>> | | struct ResolveReference (T : Expression !(R, E))
>> The compiler should have caught this, I think. You have R and E, but they aren't defined. They default to int (which is why you saw that behavior), but not being defined, they should be a compile-time error.
>>
>> The proper way to do this, unfortunately, involves static if rather than overloading. At least if you want your users to supply a single argument in all cases.
> 
> Thanks for that hint. How would such a static if look like?

template ResolveReference (T) {
   static if (is (T == Expression!(R, E))) {
   // or `static if (is (T == Expression!(R, E), R, E)) {`
      alias T* ResolveReference;
   } else {
      alias T ResolveReference;
   }
}

Except that doesn't work, right now. There's a bug listed for it.