2 variable "nested" loop with TMP

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Robin Eidissen

    2 variable "nested" loop with TMP

    What I try to do is to iterate over two variables using template
    metaprogramming . I've specialized it such that when it reaches the end
    of a row ot starts on the next and when it reaches the last row it stops..
    At least that's what I thought I did, but VC71 says "warning C4717:
    'LOOP<0,1>::DO' : recursive on all control paths, function will cause
    runtime stack overflow".
    What's wrong?

    Here's the code:
    template<int M, int N>
    class LOOP {
    private:
    template<int I, int J>
    class INNER {
    public:
    static inline void DO() {
    cout << "(" << I << "," << J << ") ";
    LOOP<I+1, J>::DO();
    }
    };
    template<int J>
    class INNER<M, J> {
    public:
    static inline void DO() {
    LOOP<0, J+1>::DO();
    }
    };
    template<int I>
    class INNER<I, N> {
    public:
    static inline void DO() {
    }
    };
    public:
    static inline void DO() {
    INNER<0, 0>::DO();
    }
    };
  • Robin Eidissen

    #2
    Re: 2 variable &quot;nested&qu ot; loop with TMP

    Robin Eidissen wrote:
    [color=blue]
    > What I try to do is to iterate over two variables using template
    > metaprogramming . I've specialized it such that when it reaches the end
    > of a row ot starts on the next and when it reaches the last row it stops..
    > At least that's what I thought I did, but VC71 says "warning C4717:
    > 'LOOP<0,1>::DO' : recursive on all control paths, function will cause
    > runtime stack overflow".
    > What's wrong?
    >
    > Here's the code:
    > template<int M, int N>
    > class LOOP {
    > private:
    > template<int I, int J>
    > class INNER {
    > public:
    > static inline void DO() {
    > cout << "(" << I << "," << J << ") ";
    > LOOP<I+1, J>::DO();
    > }
    > };
    > template<int J>
    > class INNER<M, J> {
    > public:
    > static inline void DO() {
    > LOOP<0, J+1>::DO();
    > }
    > };
    > template<int I>
    > class INNER<I, N> {
    > public:
    > static inline void DO() {
    > }
    > };
    > public:
    > static inline void DO() {
    > INNER<0, 0>::DO();
    > }
    > };[/color]
    Oh my god what a horrible mistake! I call LOOP again instead of INNER!

    Comment

    • Robin Eidissen

      #3
      Re: 2 variable &quot;nested&qu ot; loop with TMP

      But it still won't work correctly.
      On "LOOP<3, 3>::DO();" it outputs "(0,1) (0,2) (1,2)" which is decidedly
      wrong. It seems that the specializations aren't invoked at the right times.

      Comment

      • Victor Bazarov

        #4
        Re: 2 variable &quot;nested&qu ot; loop with TMP

        Robin Eidissen wrote:[color=blue]
        > But it still won't work correctly.
        > On "LOOP<3, 3>::DO();" it outputs "(0,1) (0,2) (1,2)" which is decidedly
        > wrong. It seems that the specializations aren't invoked at the right times.[/color]

        Make sure you're using the right compiler for the job. VC++ v6 is
        not up to snuff when it comes to templates.

        V

        Comment

        • Robin Eidissen

          #5
          Re: 2 variable &quot;nested&qu ot; loop with TMP

          Victor Bazarov wrote:
          [color=blue]
          > Robin Eidissen wrote:
          >[color=green]
          >> But it still won't work correctly.
          >> On "LOOP<3, 3>::DO();" it outputs "(0,1) (0,2) (1,2)" which is
          >> decidedly wrong. It seems that the specializations aren't invoked at
          >> the right times.[/color]
          >
          >
          > Make sure you're using the right compiler for the job. VC++ v6 is
          > not up to snuff when it comes to templates.
          >
          > V[/color]
          I use Visual C++ 2003.

          Comment

          • Rob Williscroft

            #6
            Re: 2 variable &quot;nested&qu ot; loop with TMP

            Robin Eidissen wrote in news:c8vs7v$93n $1@orkan.itea.n tnu.no in
            comp.lang.c++:
            [color=blue]
            > What I try to do is to iterate over two variables using template
            > metaprogramming . I've specialized it such that when it reaches the end
            > of a row ot starts on the next and when it reaches the last row it
            > stops.. At least that's what I thought I did, but VC71 says "warning
            > C4717: 'LOOP<0,1>::DO' : recursive on all control paths, function will
            > cause runtime stack overflow".
            > What's wrong?
            >
            > Here's the code:
            > template<int M, int N>
            > class LOOP {[/color]
            [color=blue]
            > public:
            > static inline void DO() {[/color]

            inline here is unnessacery function's defined inside a class
            are always inline.
            [color=blue]
            > };
            >[/color]

            With some correction's I got your version to work with an EDG compiler
            but I couldn't be bothered wating for VC 7.1 to run out of memory,
            g++ (3.4), didn't compile it either.

            This seems to work though:

            #include <iostream>
            #include <ostream>

            template< int M, int N, int I = M, int J = N >
            struct loop
            {
            template < typename F >
            static void apply( F f )
            {
            f( M - I, N - J );
            loop<M, N, I, J - 1>::apply( f );
            }
            };

            template< int M, int N, int I >
            struct loop< M, N, I, 0 >
            {
            template < typename F >
            static void apply( F f )
            {
            loop<M, N, I - 1, N>::apply( f );
            }
            };

            template< int M, int N, int J >
            struct loop< M, N, 0, J >
            {
            template < typename F >
            static void apply( F )
            {
            }
            };


            void function( int i, int j )
            {
            std::cout << "(" << i << "," << j << ") ";
            }

            int main()
            {
            loop<3, 3>::apply( function );
            }

            HTH.

            Rob.
            --

            Comment

            • Victor Bazarov

              #7
              Re: 2 variable &quot;nested&qu ot; loop with TMP

              Robin Eidissen wrote:[color=blue]
              > Victor Bazarov wrote:
              >[color=green]
              >> Robin Eidissen wrote:
              >>[color=darkred]
              >>> But it still won't work correctly.
              >>> On "LOOP<3, 3>::DO();" it outputs "(0,1) (0,2) (1,2)" which is
              >>> decidedly wrong. It seems that the specializations aren't invoked at
              >>> the right times.[/color]
              >>
              >>
              >>
              >> Make sure you're using the right compiler for the job. VC++ v6 is
              >> not up to snuff when it comes to templates.
              >>
              >> V[/color]
              >
              > I use Visual C++ 2003.[/color]

              Please post the final code that you have, describe the output you get
              and the output you would like to get. Otherwise, I am lost trying to
              merge your original (apparently incorrect) code and the corrections
              you described in replies to yourself.

              Thanks.

              V

              Comment

              • Robin Eidissen

                #8
                Re: 2 variable &quot;nested&qu ot; loop with TMP

                #include <iostream>
                using namespace std;

                template<int M, int N>
                class LOOP {
                private:
                template<int I, int J>
                class INNER {
                public:
                static inline void DO() {
                cout << "(" << I << "," << J << ") ";
                INNER<I+1, J>::DO();
                }
                };
                template<int J>
                class INNER<M, J> {
                public:
                static inline void DO() {
                INNER<0, J+1>::DO();
                }
                };
                template<>
                class INNER<0, N> {
                public:
                static inline void DO() {
                }
                };
                public:
                static inline void DO() {
                INNER<0, 0>::DO();
                }
                };

                int main() {
                LOOP<3, 3>::DO();
                return 0;
                }

                I want this to output "(0,0) (1,0) (2,0) (0,1) (1,1) (2,1) (0,2) (1,2)
                (2,2)". What is does output is: "(0,1) (0,2) (1,2)".

                Comment

                • Robin Eidissen

                  #9
                  Re: 2 variable &quot;nested&qu ot; loop with TMP

                  Thanks that worked very nicely! But for "educationa l purposes" I'd
                  appreciate it if anyone can help me out with finding the error in the
                  latest version I posted.

                  Comment

                  • Robin Eidissen

                    #10
                    Re: 2 variable &quot;nested&qu ot; loop with TMP

                    By the way, if I put "inline" in front of the "function" declaration,
                    will the entire thing be neatly unrolled with no function calls?

                    Comment

                    • Rob Williscroft

                      #11
                      Re: 2 variable &quot;nested&qu ot; loop with TMP

                      Robin Eidissen wrote in news:c905nh$efq $1@orkan.itea.n tnu.no in
                      comp.lang.c++:
                      [color=blue]
                      > By the way, if I put "inline" in front of the "function" declaration,
                      > will the entire thing be neatly unrolled with no function calls?
                      >[/color]

                      inline is only a request, so its upto the compiler and its optimiser.

                      Rob.
                      --

                      Comment

                      • Victor Bazarov

                        #12
                        Re: 2 variable &quot;nested&qu ot; loop with TMP

                        Robin Eidissen wrote:[color=blue]
                        > Thanks that worked very nicely! But for "educationa l purposes" I'd
                        > appreciate it if anyone can help me out with finding the error in the
                        > latest version I posted.[/color]

                        I'm researching it...

                        Comment

                        • Victor Bazarov

                          #13
                          Re: 2 variable &quot;nested&qu ot; loop with TMP

                          Robin Eidissen wrote:[color=blue]
                          > By the way, if I put "inline" in front of the "function" declaration,
                          > will the entire thing be neatly unrolled with no function calls?[/color]

                          'inline' is not a directive, it's a suggestion.

                          V

                          Comment

                          • Victor Bazarov

                            #14
                            Re: 2 variable &quot;nested&qu ot; loop with TMP

                            Robin Eidissen wrote:[color=blue]
                            > #include <iostream>
                            > using namespace std;
                            >
                            > template<int M, int N>
                            > class LOOP {
                            > private:
                            > template<int I, int J>
                            > class INNER {
                            > public:
                            > static inline void DO() {
                            > cout << "(" << I << "," << J << ") ";
                            > INNER<I+1, J>::DO();
                            > }
                            > };
                            > template<int J>
                            > class INNER<M, J> {
                            > public:
                            > static inline void DO() {
                            > INNER<0, J+1>::DO();
                            > }
                            > };
                            > template<>[/color]

                            Comeau C++ complains about this, says: explicit specialization is
                            not allowed in the current scope.
                            [color=blue]
                            > class INNER<0, N> {
                            > public:
                            > static inline void DO() {
                            > }
                            > };
                            > public:
                            > static inline void DO() {
                            > INNER<0, 0>::DO();
                            > }
                            > };
                            >
                            > int main() {
                            > LOOP<3, 3>::DO();
                            > return 0;
                            > }
                            >
                            > I want this to output "(0,0) (1,0) (2,0) (0,1) (1,1) (2,1) (0,2) (1,2)
                            > (2,2)". What is does output is: "(0,1) (0,2) (1,2)".[/color]

                            The first thing I thought of was pulling the 'INNER' partial
                            specialisations out of the 'LOOP' template definition, but it
                            won't work either because in order to specialise a member
                            template, one has to first specialise the template of which
                            the other is a member. So, there is no escape, and the only
                            way out is overloaded functions.

                            I rewrote your program to fist change the last index, then the
                            first one, and found that it does matter with Visual C++, but
                            probably not with Comeau C++.

                            ---------------------------------------------- Here is what I got
                            #include <iostream>
                            using namespace std;

                            template<int M, int N>
                            class LOOP {
                            template<int I, int J> struct INNER;

                            template<int I> struct INNER<I,N> {
                            static void DO() {
                            INNER<I+1,0>::D O(); // when we reach N, we move I and reset J
                            }
                            };

                            template<> struct INNER<M,0> {
                            static void DO() {} // when we moved I to match M, we bail out
                            };

                            template<int I, int J> struct INNER {
                            static void DO() {
                            cout << "(" << I << "," << J << ") ";
                            INNER<I,J+1>::D O(); // by default we move J
                            }
                            };

                            public:
                            static void DO() {
                            INNER<0,0>::DO( ); // the main one resets to the beginning...
                            }
                            };

                            template<> class LOOP<0,0> { static void DO() {} }; // in case

                            int main() {
                            LOOP<3, 3>::DO();
                            return 0;
                            }
                            --------------------------------------------------------------------------
                            However, this does not work because the 'template<>' syntax does not seem
                            to work inside the template 'LOOP' definition.

                            Visual C++ .NET (7.1) goes into infinite loop trying to compile this code,
                            and Comeau C++ refuses to compile "template<> ".

                            The syntax and the intentions of this are just as I think they should be,
                            you could ask comp.std.c++ about why 'template<>' inside a template
                            definition is not allowed, they should know.

                            Victor

                            Comment

                            • Robin Eidissen

                              #15
                              Re: 2 variable &quot;nested&qu ot; loop with TMP

                              Thanks for taking the time to check it out.

                              I asked someone who said that full specialization of nested clases was
                              not allowed by the standard(but partial specialization was), but that
                              VC7 supports it anyway.
                              Who knows why it doesn't work. It seems to me that using nested
                              templates is just asking for trouble..

                              Comment

                              Working...