Help with template specialisation syntax

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Paul Roberts

    Help with template specialisation syntax

    Hi,

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

    Here's an example:

    template<typena me T, int iclass A
    {
    static int a;
    };

    template<typena me T, int iint 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


  • Kai-Uwe Bux

    #2
    Re: Help with template specialisation syntax

    Paul Roberts wrote:
    Hi,
    >
    I'm hoping somebody here can help me with a simple problem of template
    syntax.
    >
    Here's an example:
    >
    template<typena me T, int iclass A
    {
    static int a;
    };
    >
    template<typena me T, int iint 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

    Comment

    • ivan.leben@gmail.com

      #3
      Re: Help with template specialisation syntax


      Paul Roberts wrote:
      Hi,
      >
      I'm hoping somebody here can help me with a simple problem of template
      syntax.
      >
      Here's an example:
      >
      template<typena me T, int iclass A
      {
      static int a;
      };
      >
      template<typena me T, int iint 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 iclass A
      {
      static int a;
      };

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

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

      int main(int argc, char **argv)
      {
      }

      Comment

      • Paul Roberts

        #4
        Re: Help with template specialisation syntax

        ivan.leben@gmai l.com wrote:
        You have to actually write the specialization of the class first, then
        initialize its static member:
        >
        template<class T, int iclass A
        {
        static int a;
        };
        >
        template<class Tclass A<T,0>
        {
        static int a;
        };
        >
        template<class Tint 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

        Comment

        • Kai-Uwe Bux

          #5
          Re: Help with template specialisation syntax

          Paul Roberts wrote:
          ivan.leben@gmai l.com wrote:
          >You have to actually write the specialization of the class first, then
          >initialize its static member:
          >>
          >template<cla ss T, int iclass A
          >{
          > static int a;
          >};
          >>
          >template<cla ss Tclass A<T,0>
          >{
          > static int a;
          >};
          >>
          >template<cla ss Tint 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

          Comment

          • Paul Roberts

            #6
            Re: Help with template specialisation syntax

            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 densityclass TriPatch
            {
            TriPatch* leftChild, *rightChild;
            // ... more common attributes/methods

            Point points[SomeFunctionOf( density)];
            void GenerateNewPoin ts();
            };

            template<int densityvoid TriPatch<0>::Ge nerateNewPoints ()
            {
            // unique code for density setting 0...
            points[0] = Point::Generate Point(...);
            ...
            }
            ....
            template<int densityvoid TriPatch<3>::Ge nerateNewPoints ()
            {
            // 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<typena me PointT, int densityclass TriPatch
            {
            // as above, except
            PointT points[...];
            };

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

            const int density = 2;
            TriPatch<Point, densitymyTerrai n = new TriPatch<Point, density>;
            TriPatch<WaterP oint, densitymyWater = new TriPatch<WaterP oint, density>;

            The GenerateNewPoin ts 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 GenerateNewPoin ts 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


            [1] http://www.llnl.gov/graphics/ROAM/
            [2] http://www.gameprogrammer.com/fractal.html

            Comment

            • Greg

              #7
              Re: Help with template specialisation syntax


              Paul Roberts wrote:
              Hi,
              >
              I'm hoping somebody here can help me with a simple problem of template
              syntax.
              >
              Here's an example:
              >
              template<typena me T, int iclass A
              {
              static int a;
              };
              >
              template<typena me T, int iint 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>::v alue;
              ...
              };

              Greg

              Comment

              • Paul Roberts

                #8
                Re: Help with template specialisation syntax

                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

                Comment

                • Noah Roberts

                  #9
                  Re: Help with template specialisation syntax


                  Paul Roberts wrote:
                  template<typena me T, int iclass A
                  {
                  static int a;
                  };
                  >
                  template<typena me T, int iint 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.

                  Comment

                  Working...