www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1661] New: Not possible to specialize on template with integer parameter

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661

           Summary: Not possible to specialize on template with integer
                    parameter
           Product: D
           Version: 1.023
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: wbaxter gmail.com


If you have a template that takes an integer parameter, there appears to be no
way to specialize on that integer.

Here are some examples of things that work and things that don't:

/*==========================================================================
 * specialize.d
 *    Written in the D Programming Language (http://www.digitalmars.com/d)
 */
/***************************************************************************
 * Test of specialization in D templates
 *
 * <TODO: Description>
 *
 * Author:  William V. Baxter III
 * Date: 13 Nov 2007
 * License: Public Domain
 */
//===========================================================================

module specialize;
import std.stdio;
import std.string;

struct Container(Scalar,int N)
{
    Scalar[N] values_;
}

template Container2(T) { alias Container!(T,2) Container2; }

struct Simple(T) {
    T[] data;
}

struct Number(int N) {
    const int value = N;
}

void test_specialize(T)() {
    writefln("Not so special: ", typeid(T));
}
void test_specialize(T : float)() {
    writefln("special - float");
}
void test_specialize(T : T[U], U)() {
    writefln("special - Assoc Array of %s -> %s", typeid(U), typeid(T));
}
void test_specialize(T : Container!(T,3))() {
    writefln("Ooh special - CONTAINER T,3");
}
void test_specialize(T : Simple!(T))() {
    writefln("Ooh special - SIMPLE");
}
void test_specialize(T : Number!(2))() {
    writefln("Ooh special - NUMBER = 2");
}

// Cases that don't match

// This doesn't compile
//void test_specialize(T : Number!(int N), int N)() {
//    writefln("Ooh special - NUMBER");
//}
void test_specialize(T : Number!(N), int N)() {
    writefln("Ooh special - NUMBER N");
}
void test_specialize(T : Container2!(T))() {
    writefln("Ooh special - Container2!(T)");
}
void test_specialize(T : Container!(T,N), int N)() {
    writefln("Ooh special - Container!(T,N)");
}


void main() {
    test_specialize!(int)();
    test_specialize!(float)();
    test_specialize!(float[int])();
    test_specialize!(Simple!(int))();
    test_specialize!(Number!(2))();
    test_specialize!(Container!(int,3))();

    // These don't get matched
    test_specialize!(Number!(5))();
    test_specialize!(Container!(int,2))();
    test_specialize!(Container!(int,4))();

}


-- 
Nov 12 2007
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661






Actually this should probably be "no way to specialize *around* the integer
parameter".  I.e. fixing the integer in the specialization works (sometimes,
except if the integer has been fixed using a template alias like Container2
above).  But what doesn't work is fixing the template and or other template
parameters and leaving the number as a parameter.


-- 
Nov 12 2007
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661






// This doesn't compile
void test_specialize(T : Number!(int N), int N)() {
    writefln("Ooh special - NUMBER");
}

That correctly will not compile because Number!(int N) is invalid syntax.


-- 
Feb 20 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661







 // This doesn't compile
 void test_specialize(T : Number!(int N), int N)() {
     writefln("Ooh special - NUMBER");
 }
 
 That correctly will not compile because Number!(int N) is invalid syntax.
 
I think that's part of the problem -- there *is* no valid syntax for it. For a template that takes a type you can specialize using (T:Container!(T)), but a number is not a type so (T:Container!(T)) doesn't work (at least I'm guessing that's why it doesn't work). This doesn't look like it should work either because N hasn't been defined anywhere. void test_specialize(T : Number!(N))() { writefln("Ooh special - NUMBER N"); } But it does compile. I tried the Number!(int N) version just because that looks like a reasonable syntax for saying "hey we're introducing a new integer parameter named N here". This affects code that uses templates to implement fixed-size vectors and operations on them. It came up when I was trying to implement Vector/Matrix classes in OpenMesh/D: http://www.dsource.org/projects/openmeshd/browser/trunk/OpenMeshD/OpenMesh/Core/Geometry/MatrixT.d http://www.dsource.org/projects/openmeshd/browser/trunk/OpenMeshD/OpenMesh/Core/Geometry/VectorT.d I don't remember exactly where I ran into it, but if you've got a Vector!(N) it's pretty natural to want to write a template that matches only Vector! but for any N. If you're writing a template _function_ you can work around it by putting the type as one of the function args. But it's not always the case (for instance if you want to make a Traits class specialized on Vector!(N). --
Feb 20 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661


bugzilla digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |DUPLICATE





This is exactly the same issue as 1454, but with values instead of types. It's
intractable for the same reasons.

*** This bug has been marked as a duplicate of 1454 ***


-- 
Feb 20 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661


wbaxter gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|DUPLICATE                   |





I seem to have been wrong in using function templates.  C++ can't do that
either.  I think I must have thought it was simpler to demonstrate with
functions when I tried to distill a test case from the original C++ to D.  But
it does work with structs in C++, intractible or not.

Working C++ (save to specialize.cpp and compile with "dmc specialize.cpp"):

#include <stdio.h>

template <int N>
struct Number {
    static const int value = N;
};

template <typename T>
struct test_specialize 
{
    void talk() { printf("Not so special:\n"); }
};

template<int N>
struct test_specialize<Number<N> > 
{
    void talk() { printf("Ooh special - NUMBER N\n"); }
};

int main(int argc, char* argv[])
{
    test_specialize< Number<5> > x;
    x.talk();
    return 0;
}

-----

Not working D:

module specialize;
import std.stdio;

struct Number(int N) 
{
    const int value = N;
}

struct test_specialize(T)
{
    void talk() { writefln("Not so special:\n"); }
}

struct test_specialize(T : Number!(N))
{
    void talk() { writefln("Ooh special - NUMBER N\n"); }
}

int main()
{
    test_specialize!(Number!(5)) x;
    x.talk();
    return 0;
}

---

The C++ version outputs "ooh special", and the d version "Not so special".


-- 
Feb 21 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661






Ok, I agree that that's a bug. I'll fix it.


-- 
Feb 21 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661






Am I right in thinking this is the actual syntax that should work?:

struct test_specialize(T : Number!(N), int N)
{
    void talk() { writefln("Ooh special - NUMBER N\n"); }
}
test_specialize!(Number!(5)) x;


That's a minor variation on an example in the docs:

  template Foo(T: T[U], U)
  {
      ... 
  }
  Foo!(int[long]) // instantiates Foo with T set to int, U set to long


(But the int-arg version still doesn't work, I'm just checking that the above
is what *should* work.)


-- 
Feb 29 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661







 Am I right in thinking this is the actual syntax that should work?:
 
 struct test_specialize(T : Number!(N), int N)
 {
     void talk() { writefln("Ooh special - NUMBER N\n"); }
 }
 test_specialize!(Number!(5)) x;
I would expect it to be. But this issue isn't limited to int parameters. Other primitive types don't work either. Also, more complex pattern matching fails: struct a(S, T) {} struct b(T : a!(N, a!(N, int)), N) {} alias a!(float,int) A; alias a!(float, A) B; b!(B, float) x; // fails, and so does b!(B) x; foo.d:5: template instance b!(a!(float,a!(float,int) ) ,float) does not match any template declaration foo.d:5: Error: b!(a!(float,a!(float,int) ) ,float) is used as a type foo.d:5: variable foo.x voids have no value This is a bit problematic for someone creating a new compiler for D since it's not really clear how complex types the language should be able to match. The specification only mentions (http://www.digitalmars.com/d/1.0/template.html) that they should be types. But that's a bit confusing since Number!(N) isn't a valid type. You can't e.g. alias it, there's no parametrized alias syntax: alias IntNPair N = tuple!(int, N); One could instantiate the code above with Number(float) or Number!(float), and get tuple!(int, float). --
Feb 29 2008
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1661


bugzilla digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|                            |FIXED





Fixed dmd 1.028 and 2.012


-- 
Mar 06 2008