The C preprocessor delivers the desired result, but is ugly.
Template metaprogramming delivers results I do not understand.
Can anyone explain why loop unrolling doesn't play well with templates?
Or better, can someone submit a code fragment to get desired results?
Here are the command-lines I use to generate code:
"g++ -DTEMPLATE=0 -o gotofun0 gotofun.cpp" works exactly as desired.
"g++ -DTEMPLATE=1 -o gotofun1 gotofun.cpp" fails to output properly.
"g++ -DTEMPLATE=2 -o gotofun2 gotofun.cpp" fails to output properly.
When correct, the program should generate a countdown sequence.
For instance, running the program gotofun0, the output is 3 2 1.
The programs gotofun1 and gotofun2 countdown past 0, down to -252.
It is as if the "end:" label only applies to the first line from the unrolling.
I have tried various uses of brace-blocking, parens, and whatnot.
Any help would be appreciated.
Expand|Select|Wrap|Line Numbers
- /// gotofun.cpp
- /// goto considered fun
- /// @date 12/31/2007
- /// @brief This code counts down from a specified number using computed gotos.
- #include <iostream>
- using namespace std;
- #ifndef TEMPLATE
- #define TEMPLATE 0
- #endif
- #if ( 0 == TEMPLATE )
- /// C preprocessor version works fine.
- #define go1 cout << count-- << endl
- #define go2 ((go1),(go1))
- #define go4 ((go2),(go2))
- #define go8 ((go4),(go4))
- #define go16 ((go8),(go8))
- #define go32 ((go16),(go16))
- #define go64 ((go32),(go32))
- #define go128 ((go64),(go64))
- #define go256 ((go128),(go128))
- #endif
- #if ( 1 == TEMPLATE ) /// Don't yet know how to make template metaprogramming version work.
- template<int N>
- static inline void GO ( int &n ) { cout << n-- << endl; GO<N-1>( n ); }
- template< >
- static inline void GO<1>( int &n ) { cout << n-- << endl; }
- #define go1 GO< 1>( count );
- #define go256 GO<256>( count );
- #endif
- #if ( 2 == TEMPLATE ) /// Don't yet know how to make template metaprogramming version work.
- template<int N>
- struct Q { static inline void q( int &n ) { cout << n-- << endl; Q< N-1 >::q( n ); } };
- template< >
- struct Q< 1 >{ static inline void q( int &n ) { cout << n-- << endl; } };
- #define go1 Q< 1>::q( count )
- #define go256 Q<256>::q( count )
- #endif
- int main( int argc, char **argv ) {
- try {
- char *u = (char *) &&unused, *b = (char *) &&begin, *e = (char *) &&end;
- int d = ( b - u ); ///< Code size between labels
- int n = ( e - b ) / d;
- void *jump[ n + 1 ]; ///< Make a jump table
- for( int i = 0; i < ( n + 1 ); ++i ) /// Generate jump table contents.
- jump[ i ] = (void *)( b + ( i * d ) );
- if( jump[ n ] != &&end ) throw( "Failed to generate jump table" );
- cout << n << " table entries of width " << d << endl;
- cout << &&unused << ", " << &&begin << ", " << &&end << endl;
- cout << (void *)u << ", " << (void *)b << ", " << (void *)e << endl;
- int count; ///< Number to count-down
- if( argc == 2 ) count = atoi( argv[ 1 ] );
- if( argc != 2 || count < 0 )
- throw( "Please provide exactly one positive integer arg." );
- goto *( jump[ n - ( count % n ) ] ); /// partway through table.
- unused: go1;
- begin: go256;
- end: if( count > 0 ) goto begin; ///< If more, go back and do it.
- }
- catch( const char *s) {
- cerr << "Error: " << s << endl;
- }
- catch( ... ) {
- cerr << "Error: unknown" << endl;
- }
- return 0;
- }