By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,856 Members | 1,986 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,856 IT Pros & Developers. It's quick & easy.

2 variable "nested" loop with TMP

P: n/a
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();
}
};
Jul 22 '05 #1
Share this Question
Share on Google+
15 Replies


P: n/a
Robin Eidissen wrote:
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();
}
};

Oh my god what a horrible mistake! I call LOOP again instead of INNER!
Jul 22 '05 #2

P: n/a
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.
Jul 22 '05 #3

P: n/a
Robin Eidissen wrote:
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.


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

V
Jul 22 '05 #4

P: n/a
Victor Bazarov wrote:
Robin Eidissen wrote:
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.

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

V

I use Visual C++ 2003.
Jul 22 '05 #5

P: n/a
Robin Eidissen wrote in news:c8**********@orkan.itea.ntnu.no in
comp.lang.c++:
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 { public:
static inline void DO() {
inline here is unnessacery function's defined inside a class
are always inline.
};


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.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #6

P: n/a
Robin Eidissen wrote:
Victor Bazarov wrote:
Robin Eidissen wrote:
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.


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

V


I use Visual C++ 2003.


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
Jul 22 '05 #7

P: n/a
#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)".
Jul 22 '05 #8

P: n/a
Thanks that worked very nicely! But for "educational purposes" I'd
appreciate it if anyone can help me out with finding the error in the
latest version I posted.
Jul 22 '05 #9

P: n/a
By the way, if I put "inline" in front of the "function" declaration,
will the entire thing be neatly unrolled with no function calls?
Jul 22 '05 #10

P: n/a
Robin Eidissen wrote in news:c9**********@orkan.itea.ntnu.no in
comp.lang.c++:
By the way, if I put "inline" in front of the "function" declaration,
will the entire thing be neatly unrolled with no function calls?


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

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #11

P: n/a
Robin Eidissen wrote:
Thanks that worked very nicely! But for "educational purposes" I'd
appreciate it if anyone can help me out with finding the error in the
latest version I posted.


I'm researching it...
Jul 22 '05 #12

P: n/a
Robin Eidissen wrote:
By the way, if I put "inline" in front of the "function" declaration,
will the entire thing be neatly unrolled with no function calls?


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

V
Jul 22 '05 #13

P: n/a
Robin Eidissen wrote:
#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<>
Comeau C++ complains about this, says: explicit specialization is
not allowed in the current scope.
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)".


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>::DO(); // 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>::DO(); // 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
Jul 22 '05 #14

P: n/a
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..
Jul 22 '05 #15

P: n/a
Robin Eidissen wrote in news:c9**********@orkan.itea.ntnu.no in
comp.lang.c++:
Thanks that worked very nicely! But for "educational purposes" I'd
appreciate it if anyone can help me out with finding the error in the
latest version I posted.


I fixed you previous version but VC 7.1 will *not* compile it.

AFAICT the only error in your current version is the explicit
specialization.

I Compiled and ran your code with CBuildeX (preview) it gave:

(0,0) (1,0) (2,0) (0,1) (1,1) (2,1) (0,2) (1,2) (2,2)

It does compile in microsoft extensions mode, which is why
it didn't complain about the explicit specialization.

Note that CBuildeX and Comaeu both have EDG frontends, this
compiler is possibly the only current compiler that reliably selects
the right specialization when instantiating templates with integral
arguments.

You have two choces:

- *always* Count to 0. As my example did.

- For even greater portability use boost::mpl::int_ for
all your meta-programming/counting needs.

This library replace integers with types, thus sidesteping
the problem entirely

http://www.boost.org/libs/mpl/doc/re...t_classes.html

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #16

This discussion thread is closed

Replies have been disabled for this discussion.