Help with template specialisation syntax

Discussion in 'C++' started by Paul Roberts, Sep 9, 2006.

  1. Paul Roberts

    Paul Roberts Guest

    Hi,

    I'm hoping somebody here can help me with a simple problem of template
    syntax.

    Here's an example:

    template<typename T, int i> class A
    {
    static int a;
    };

    template<typename T, int i> int A<T, 0>::a = 3;

    Here, I'm trying to specialise T for the case where i is 0.

    MSVC (8.0) reports this error on the last line: "template argument list
    following class template name must list parameters in the order used in
    template parameter list".

    As far as I can see, the lists *do* list their parameters in the same order!

    I've consulted Stroustup (2nd Ed) and the other C++ books I have, but I
    can't find a similar partial specialisation example to learn from. In
    simpler specialisation examples, they leave out the first parameter list
    (giving just template<>), but if I do this, then T isn't recognised
    later on in the same line. If I give "typename T" but omit "int i", then
    the compiler says I have too few template parameters for T.

    What's the proper syntax for this particular kind of specialisation?

    Many thanks to anyone who can assist.


    --
    Paul Roberts
    www.m3fe.com
    Paul Roberts, Sep 9, 2006
    #1
    1. Advertising

  2. Paul Roberts

    Kai-Uwe Bux Guest

    Paul Roberts wrote:

    > Hi,
    >
    > I'm hoping somebody here can help me with a simple problem of template
    > syntax.
    >
    > Here's an example:
    >
    > template<typename T, int i> class A
    > {
    > static int a;
    > };
    >
    > template<typename T, int i> int A<T, 0>::a = 3;
    >
    > Here, I'm trying to specialise T for the case where i is 0.

    [snip]

    You are missing the actual specialization of the class:

    template < typename T, int i >
    class A {
    static int a;
    };

    template < typename T >
    class A<T,0> {
    static int a;
    };

    template < typename T >
    int A<T, 0>::a = 3;



    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Sep 9, 2006
    #2
    1. Advertising

  3. Paul Roberts

    Guest

    Paul Roberts wrote:
    > Hi,
    >
    > I'm hoping somebody here can help me with a simple problem of template
    > syntax.
    >
    > Here's an example:
    >
    > template<typename T, int i> class A
    > {
    > static int a;
    > };
    >
    > template<typename T, int i> int A<T, 0>::a = 3;
    >
    > Here, I'm trying to specialise T for the case where i is 0.
    >
    > MSVC (8.0) reports this error on the last line: "template argument list
    > following class template name must list parameters in the order used in
    > template parameter list".
    >
    > As far as I can see, the lists *do* list their parameters in the same order!
    >
    > I've consulted Stroustup (2nd Ed) and the other C++ books I have, but I
    > can't find a similar partial specialisation example to learn from. In
    > simpler specialisation examples, they leave out the first parameter list
    > (giving just template<>), but if I do this, then T isn't recognised
    > later on in the same line. If I give "typename T" but omit "int i", then
    > the compiler says I have too few template parameters for T.
    >
    > What's the proper syntax for this particular kind of specialisation?
    >
    > Many thanks to anyone who can assist.
    >
    >
    > --
    > Paul Roberts
    > www.m3fe.com


    You have to actually write the specialization of the class first, then
    initialize its static member:

    template<class T, int i> class A
    {
    static int a;
    };

    template<class T> class A<T,0>
    {
    static int a;
    };

    template<class T> int A<T, 0>::a = 3;

    int main(int argc, char **argv)
    {
    }
    , Sep 9, 2006
    #3
  4. Paul Roberts

    Paul Roberts Guest

    wrote:
    > You have to actually write the specialization of the class first, then
    > initialize its static member:
    >
    > template<class T, int i> class A
    > {
    > static int a;
    > };
    >
    > template<class T> class A<T,0>
    > {
    > static int a;
    > };
    >
    > template<class T> int A<T, 0>::a = 3;
    >
    > int main(int argc, char **argv)
    > {
    > }
    >


    Thank you both for your quick replies.

    I want the specialized classes A<T, 0>, A<T, 1>, A<T, 2>, ... to all
    have the same members (i.e. those in the general A<T, i>). Assuming I
    don't want to use inheritance, do I have to duplicate A's entire
    contents inside each specialisation? Or is there a shortcut?

    Thanks again,

    --
    Paul Roberts
    www.m3fe.com
    Paul Roberts, Sep 9, 2006
    #4
  5. Paul Roberts

    Kai-Uwe Bux Guest

    Paul Roberts wrote:

    > wrote:
    >> You have to actually write the specialization of the class first, then
    >> initialize its static member:
    >>
    >> template<class T, int i> class A
    >> {
    >> static int a;
    >> };
    >>
    >> template<class T> class A<T,0>
    >> {
    >> static int a;
    >> };
    >>
    >> template<class T> int A<T, 0>::a = 3;
    >>
    >> int main(int argc, char **argv)
    >> {
    >> }
    >>

    >
    > Thank you both for your quick replies.
    >
    > I want the specialized classes A<T, 0>, A<T, 1>, A<T, 2>, ... to all
    > have the same members (i.e. those in the general A<T, i>). Assuming I
    > don't want to use inheritance, do I have to duplicate A's entire
    > contents inside each specialisation? Or is there a shortcut?


    Why do you want to avoid inheritance? Anyway, if you want the only
    difference to be in the initialization of static variables, you could do
    something like:

    template < typename T, int i >
    struct A {
    static int a;
    };

    int init_A_a ( int i ) {
    return ( i + 3 );
    }

    template < typename T, int i >
    int A<T,i>::a = init_A_a( i );


    #include <iostream>

    int main ( void ) {
    std::cout << A<int,2>::a << '\n';
    }


    However, I am curious: what is the underlying problem that this design is
    supposed to solve? Maybe there is a different approach altogether.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Sep 9, 2006
    #5
  6. Paul Roberts

    Paul Roberts Guest

    Kai-Uwe Bux wrote:
    <snip>
    > However, I am curious: what is the underlying problem that this design is
    > supposed to solve? Maybe there is a different approach altogether.
    >
    >


    I'll try to summarise as briefly as possible, but it's still going to be
    quite long, so feel free to retract the offer of help if your curiosity
    wanes :)

    I am working with a planet-sized fractal terrain with dynamic level of
    detail, represented by a binary tree of triangular "patches". I use a
    variant of the ROAM algorithm[1] to construct this tree. I have a class
    representing such a patch - let's call it TriPatch. The algorithm that
    turns a TriPatch into actual rendered triangles can work at one of four
    global "density" settings - each higher density level stores more
    vertices (call them Points) per patch, so I templated TriPatch as follows:

    template<int density> class TriPatch
    {
    TriPatch* leftChild, *rightChild;
    // ... more common attributes/methods

    Point points[SomeFunctionOf(density)];
    void GenerateNewPoints();
    };

    template<int density> void TriPatch<0>::GenerateNewPoints()
    {
    // unique code for density setting 0...
    points[0] = Point::GeneratePoint(...);
    ...
    }
    ....
    template<int density> void TriPatch<3>::GenerateNewPoints()
    {
    // unique code for density setting 3...
    }

    Now, I want to reuse the terrain code to render water (effectively as a
    "flat" terrain), sharing the same basic binary tree structure and
    operations.

    The Points stored inside each TriPatch are generated by a fractal
    algorithm (midpoint displacement[2]) that takes surrounding vertices as
    input. The vertices store fractal seeds along with their 3D positions.
    With water, though, the vertex generation code will not apply a fractal
    perturbation, and no fractal parameters will be stored at each vertex.

    So, my plan was to create a distinct WaterPoint type (with its own
    implementation of GenPoint), and to further templatise TriPatch on the
    point type:

    template<typename PointT, int density> class TriPatch
    {
    // as above, except
    PointT points[...];
    };

    Terrain and water binary trees could then be initialised as follows:

    const int density = 2;
    TriPatch<Point, density> myTerrain = new TriPatch<Point, density>;
    TriPatch<WaterPoint, density> myWater = new TriPatch<WaterPoint, density>;

    The GenerateNewPoints method given above remains the same regardless of
    the point type used, since it calls PointT's own GenPoint for the actual
    generation. It needs to be specialised only for /density/, hence the
    example in my original post where we specialised on the non-type
    parameter, while the type parameter remained unspecified.

    Now, to achieve my "terrain patch" and "water patch" types I could
    simply duplicate the bin-tree structure and associated algorithms, but
    since these make up most of the code, and are identical in both cases, I
    felt that I should strive for shared code. Since I am potentially
    calling methods on many thousands of TriPatches per frame (at 60 frames
    per second), I don't want methods like GenerateNewPoints to be virtual
    functions. And since the density setting and vertex generation algorithm
    for any particular tree of TriPatches is known at compile-time, I
    figured this was an ideal situation for templates.

    I'm trying to find a solution that maximises performance and code
    re-use, while remaining fairly readable. If there is a different
    approach that satisfies these criteria, I'd be happy to hear about it!

    Thanks if you read this far :)

    --
    Paul Roberts
    www.m3fe.com

    [1] http://www.llnl.gov/graphics/ROAM/
    [2] http://www.gameprogrammer.com/fractal.html
    Paul Roberts, Sep 10, 2006
    #6
  7. Paul Roberts

    Greg Guest

    Paul Roberts wrote:
    > Hi,
    >
    > I'm hoping somebody here can help me with a simple problem of template
    > syntax.
    >
    > Here's an example:
    >
    > template<typename T, int i> class A
    > {
    > static int a;
    > };
    >
    > template<typename T, int i> int A<T, 0>::a = 3;
    >
    > Here, I'm trying to specialise T for the case where i is 0.
    >
    > MSVC (8.0) reports this error on the last line: "template argument list
    > following class template name must list parameters in the order used in
    > template parameter list".
    >
    > As far as I can see, the lists *do* list their parameters in the same order!


    A straightforward solution would be to create a "helper" class
    template, say, ConstantA, to specify the appropriate value for "a" for
    each int value:

    template <int N>
    struct ConstantA;

    template <>
    struct ConstantA<0>
    {
    const static int value = 3;
    };

    template <>
    struct ConstantA<1>
    {
    const static int value = 8;
    };

    and so forth. Then declare the general class template for A, using
    ConstantA to supply a's value:

    template <int N>
    struct A
    {
    static const int a = ConstantA<N>::value;
    ...
    };

    Greg
    Greg, Sep 10, 2006
    #7
  8. Paul Roberts

    Paul Roberts Guest

    Greg wrote:
    > A straightforward solution would be to create a "helper" class
    > template, say, ConstantA, to specify the appropriate value for "a" for
    > each int value:
    >

    <snip>

    I now have a working solution based on your suggestion. Thanks!

    --
    Paul Roberts
    www.m3fe.com
    Paul Roberts, Sep 11, 2006
    #8
  9. Paul Roberts

    Noah Roberts Guest

    Paul Roberts wrote:

    > template<typename T, int i> class A
    > {
    > static int a;
    > };
    >
    > template<typename T, int i> int A<T, 0>::a = 3;


    To specialize a template you put the parameters the new specialization
    takes in the first list and pass the parameters you want to the
    original template. So, if you are trying to default i to 0 you can
    think of it as creating a new template that accepts one typename
    parameter:

    template < typename T >
    // Now pass the appropriate arguments to the template you are
    specializing:
    int A<T, 0>::a = 3;

    Note that if you are specializing fully, as in no arguments left, you
    would have a "new" template that accepts no parameters:

    template <>
    // and then pass the appropriate arguments to the original template:
    int A<int, 0>::a = 3;

    And of course your standard definition (the one for everything
    unspecialized) is also a "new" template that accepts the same amount of
    parameters as the old:

    template < typename T, int i >
    int A<T, i>::a = 3;

    Now, you aren't really creating "new" templates (hense the quotes) but
    it can help to think of it that way. The point is that the list to
    your template definition is the parameters that are left to take and
    then you pass the necissary parameters, including ones that you don't
    take in and the ones you do, off to the template you are specializing.
    Noah Roberts, Sep 11, 2006
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben
    Replies:
    1
    Views:
    327
    Victor Bazarov
    Aug 12, 2003
  2. Lars Yencken

    Re: Template specialisation problem

    Lars Yencken, Aug 20, 2003, in forum: C++
    Replies:
    6
    Views:
    2,502
    Lars Yencken
    Aug 21, 2003
  3. Tim Clacy
    Replies:
    12
    Views:
    613
    Dan W.
    Dec 3, 2003
  4. Nicolas Weidmann
    Replies:
    1
    Views:
    308
    Christian Jaeger
    Feb 17, 2004
  5. Martin MacRobert
    Replies:
    2
    Views:
    455
    Terje Slettebø
    Aug 2, 2004
Loading...

Share This Page