C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Template M.P. -- why won't this work?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Carlos Moreno
Guest





PostPosted: Mon Sep 05, 2005 11:10 am    Post subject: Template M.P. -- why won't this work? Reply with quote




I'm struggling with this meta-loop I'm trying to do (basically,
I'm trying to write a "simple" example of a loop unrolled by meta-
programming).

Instead of the typical approach of going down from an int N all
the way to 1 and provide the specialized version for N=1, I want
a loop that goes from N to M (where N and M are arbitrary integer
values -- known at compile-time, of course, and with M > N)

So, I create a wrapper class that uses N and M as non-type params.
But it won't compile. Here's the code (I'm omiting the #include
and the using namespace):

template <int N, int M>
class metaloop
{
template <int X, typename T>
struct pass
{
static void go ()
{
cout << X << 't' << X*X << endl;
metaloop }
};

template <typename T>
struct pass<M,T>
{
static void go ()
{}
// M is excluded (following the usual semi-open
// loops -- as in for (i = N; i < M ... )
};

public:
static void go ()
{
pass }
};

int main()
{
metaloop<2,10>::go();

return 0;
}


The compiler complains at the point of pass<501,int>. It fails to grab
the specialization pass<M,T>, which in this case would be pass<10,int>,
and instead, it takes the same generic one, which invokes pass<11,int>,
which invokes pass<12,int>.... At 501, the compiler apparently reaches
its recursion limit and reports the error.

Why is that? What am I missing?


Thanks,

Carlos
--

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Gleb Alexeev
Guest





PostPosted: Tue Sep 06, 2005 10:48 am    Post subject: Re: Template M.P. -- why won't this work? Reply with quote



I don't have direct answer to your question but IMHO you seem to
overcomplicate things given your task.
Maybe solution below is what you need?

template <int N, int M>
class metaloop {
public:
static void go () {
std::cout << N << std::endl;
metaloop }
};
template <int M>
class metaloop<M,M> {
public:
static void go () {
}
};


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Greg Herlihy
Guest





PostPosted: Tue Sep 06, 2005 10:54 am    Post subject: Re: Template M.P. -- why won't this work? Reply with quote



Carlos Moreno wrote:
Quote:
I'm struggling with this meta-loop I'm trying to do (basically,
I'm trying to write a "simple" example of a loop unrolled by meta-
programming).

Instead of the typical approach of going down from an int N all
the way to 1 and provide the specialized version for N=1, I want
a loop that goes from N to M (where N and M are arbitrary integer
values -- known at compile-time, of course, and with M > N)

So, I create a wrapper class that uses N and M as non-type params.
But it won't compile. Here's the code (I'm omiting the #include
and the using namespace):

template <int N, int M
class metaloop
{
template struct pass
{
static void go ()
{
cout << X << 't' << X*X << endl;
metaloop }
};

template <typename T
struct pass {
static void go ()
{}
// M is excluded (following the usual semi-open
// loops -- as in for (i = N; i < M ... )
};

public:
static void go ()
{
pass }
};

int main()
{
metaloop<2,10>::go();

return 0;
}


The compiler complains at the point of pass<501,int>. It fails to grab
the specialization pass<M,T>, which in this case would be pass<10,int>,
and instead, it takes the same generic one, which invokes pass<11,int>,
which invokes pass<12,int>.... At 501, the compiler apparently reaches
its recursion limit and reports the error.

Why is that? What am I missing?


Thanks,

Carlos
--

It is not possible to specialize a class template nested inside a class
template that is itself not specialized. Furthermore the nested class
template pass is declared private which will make it inaccessible from
the other instantiations of metaloop used in the loop.

When writing template meta-programs, always strive for simplicity
(don't laugh). In this case, the nested template only complicates the
implementation of the recursive go routine. I would suggest using just
one class template to implement the metaloop:

using std::cout;

template <int Counter, int Limit>
class MetaLoop
{
public:
static void Go()
{
cout << Counter << 't' << Counter*Counter << std::endl;

MetaLoop }
};

template <int Limit>
class MetaLoop<Limit, Limit>
{
public:
static void Go()
{
}
};

int main()
{
MetaLoop<2, 10>::Go();

return 0;
}

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Frank Chang
Guest





PostPosted: Tue Sep 06, 2005 10:56 am    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

Carlos, I made the following changes. This should run OK:

template <int N, int M>
class metaloop
{
public:
template <int X, typename T>
struct pass
{
static void go ()
{
cout << X << 't' << X*X << endl;

metaloop
}
};

template <typename T>
struct pass<M,T>
{
static void go ()
{}
// M is excluded (following the usual semi-open
// loops -- as in for (i = N; i < M ... )
};



static void go ()
{
pass }
};

// here I hard code a explicit template specialization
// to stop the infinite recursion you are experiencing.
// It must use hard-coded integers

template<>
class metaloop<10, 10> {
public:

template <int X, typename T>
struct pass
{
static void go ()
{
cout << "end of recursion" << endl;

}
};
};



Thank you.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Marc Mutz
Guest





PostPosted: Tue Sep 06, 2005 11:05 am    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

Carlos Moreno wrote:

Quote:
metaloop<N,M>::pass<X+1,T>::go();

Not related to your OQ, but for gcc 4.0, I need to write
this as
typedef
typename metaloop<N,M>::template pass<X+1,T> next_pass;
next_pass::go();

Marc


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Carl Barron
Guest





PostPosted: Tue Sep 06, 2005 11:06 am    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

Carlos Moreno <moreno_at_mochima_dot_com (AT) xx (DOT) xxx> wrote:

Quote:
I'm struggling with this meta-loop I'm trying to do (basically,
I'm trying to write a "simple" example of a loop unrolled by meta-
programming).

Instead of the typical approach of going down from an int N all
the way to 1 and provide the specialized version for N=1, I want
a loop that goes from N to M (where N and M are arbitrary integer
values -- known at compile-time, of course, and with M > N)

So, I create a wrapper class that uses N and M as non-type params.
But it won't compile. Here's the code (I'm omiting the #include
and the using namespace):

template <int N, int M
class metaloop
{
template struct pass
{
static void go ()
{
cout << X << 't' << X*X << endl;
metaloop }
};

template <typename T
struct pass {
static void go ()
{}
// M is excluded (following the usual semi-open
// loops -- as in for (i = N; i < M ... )
};

public:
static void go ()
{
pass }
};

int main()
{
metaloop<2,10>::go();

return 0;
}


The compiler complains at the point of pass<501,int>. It fails to grab
the specialization pass<M,T>, which in this case would be pass<10,int>,
and instead, it takes the same generic one, which invokes pass<11,int>,
which invokes pass<12,int>.... At 501, the compiler apparently reaches
its recursion limit and reports the error.

Why is that? What am I missing?

inner classes as template params maybe. but the easiest solution

is to remove the looping from pass and let it handle the body of the
loop then a specialsation of the looping template is easy. Here is
one solution:

#include <iostream>

template <int X,typename T>
struct pass
{
static void go()
{ // just do one item, looping below.
std::cout << X*X << 'n';
}
};

template struct do_loop
{
static void go()
{
pass<Start,T>::go();
do_loop<Start+1,Fini,T>::go();
}
};

template <int Start,typename T>
struct do_loop<Start,Start,T>
{
static void go()
{
pass<Start,T>::go();
}
};

int main()
{
do_loop<4,10,int>::go();
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Carlos Moreno
Guest





PostPosted: Tue Sep 06, 2005 4:14 pm    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

Greg Herlihy wrote:

Quote:
It is not possible to specialize a class template nested inside a class
template that is itself not specialized. Furthermore the nested class
template pass is declared private which will make it inaccessible from
the other instantiations of metaloop used in the loop.

Oh, d'oh!! This last detail was an oversight -- I was thinking in
terms of the outer class, and saw it as it was that outer class the
one that had to access the other instantiations... (I think the
compiler would have recognized that the class was there and would
have told me that it was private -- if there wasn't the other problem,
that is)

Quote:
When writing template meta-programs, always strive for simplicity
(don't laugh).

Don't worry. I see that the irony is not lost on you :-)

Quote:
In this case, the nested template only complicates the
implementation of the recursive go routine.

The responsibility of the outer class was to create the specialized
version for the upper limit, so that I didn't have to do it explicitly
(that would completely defy the purpose of the exercise I was doing).

Quote:
template <int Limit
class MetaLoop

Neat trick!! I had not seen a way to "automatically" specialize the
upper limit -- the first solution that came to mind was obviously
specializing metaloop<10>, but then what's the point of writing
such thing, if I need to re-write the whole thing each time that
I want to use it? That's why the next solution that I could think
of involved the nested classes, to have one "middle-man" automate
that part for me.

Thanks for the trick!

Carlos
--

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
graeme prentice
Guest





PostPosted: Wed Sep 07, 2005 2:01 pm    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

On 6 Sep 2005 06:54:25 -0400, Greg Herlihy wrote:

Quote:

It is not possible to specialize a class template nested inside a class
template that is itself not specialized.

This applies only to explicit specializations. Carlos's code uses a
partial specialization - which is perfectly legal. See 14.5.4.3/2 for
an example.

FWIW - VC7.1 locks up compiling this code, consuming 98% CPU and
increasing memory, requiring task manager to kill it.

Graeme

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Frank Chang
Guest





PostPosted: Wed Sep 07, 2005 5:14 pm    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

Graeme, Using the following template class in MSVC7.1, It compiles it
less than a second , VC7.1 does not lock up and does not requires
increasing memory. Is this the template class you are using? Thank you.

template <int N, int M>
class metaloop
{
public:
template <int X, typename T>
struct pass
{
static void go ()
{
cout << X << 't' << X*X << endl;

metaloop }
};

template <typename T>
struct pass<M,T>
{
static void go ()
{}
// M is excluded (following the usual semi-open
// loops -- as in for (i = N; i < M ... )
};


public:
static void go ()
{
pass }
};

template<int M>
class metaloop<M, M> {
public:
template <int X, typename T>
struct pass
{
static void go ()
{
cout << "end of recursion" << endl;
}
};
}


int _tmain(int argc, _TCHAR* argv[])
{
metaloop<2, 1000>::go();
}


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
graeme prentice
Guest





PostPosted: Thu Sep 08, 2005 9:16 am    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

On 7 Sep 2005 13:14:27 -0400, Frank Chang wrote:

Quote:
Graeme, Using the following template class in MSVC7.1, It compiles it
less than a second , VC7.1 does not lock up and does not requires
increasing memory. Is this the template class you are using? Thank you.


No, it locks up using Carlos's code. Your code has syntax errors but if
I correct them, it compiles without locking up. If I change the
following line back to what Carlos had, it locks up.

// no lock up
metaloop<N+1,M>::pass<X+1,T>::go();

// locks up VC7.1
metaloop<N,M>::pass<X+1,T>::go();

Graeme

Quote:

template <int N, int M
class metaloop
{
public:
template struct pass
{
static void go ()
{
cout << X << 't' << X*X << endl;

metaloop }
};

template <typename T
struct pass {
static void go ()
{}
// M is excluded (following the usual semi-open
// loops -- as in for (i = N; i < M ... )
};


public:
static void go ()
{
pass }
};

template<int M
class metaloop public:
template <int X, typename T
struct pass
{
static void go ()
{
cout << "end of recursion" << endl;
}
};
}


int _tmain(int argc, _TCHAR* argv[])
{
metaloop<2, 1000>::go();
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Frank Chang
Guest





PostPosted: Thu Sep 08, 2005 2:09 pm    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

Graeme, I believe you are stating that :

metaloop<N,M>::pass<X+1,T>::go­(); locks up VC7.1

This is because of infinite recursion.I experienced the same problem.

But metaloop<N+1,M>::pass<X+1,T>::­go();
does not lock , because we advance N -> N + 1 , therefore eventually
N=M and the recursion stops because the compiler sees the explicit
template specialization : template<int M>
class metaloop<M, M>

Please tell me what the compiler errors were and how you fixed
them. Thank you.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Graeme Prentice
Guest





PostPosted: Sat Sep 10, 2005 12:34 am    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

On 8 Sep 2005 10:09:23 -0400, Frank Chang wrote:

Quote:
Graeme, I believe you are stating that :

metaloop<N,M>::pass<X+1,T>::go­(); locks up VC7.1

yep, that's what I said, (except for the mysterious minus sign)


Quote:

This is because of infinite recursion.I experienced the same problem.

No it's not. It's because of a bug in VC7.1. There's no infinite
recursion in Carlos's code as long as N is less than M (and this could
be protected with the help of boost-static-assert). The nested classes
could be a bit expensive memory-wise though, depending on the compiler's
optimisation skills.


Quote:

But metaloop<N+1,M>::pass<X+1,T>::­go();
does not lock , because we advance N -> N + 1 , therefore eventually
N=M and the recursion stops because the compiler sees the explicit
template specialization : template<int M
class metaloop
Please tell me what the compiler errors were and how you fixed
them. Thank you.

IIRC, you lost a semicolon, didn't include accessed members of namespace std that weren't visible. (Also _tmain
and _TCHAR are non standard).

Graeme

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Frank Chang
Guest





PostPosted: Mon Sep 12, 2005 2:52 pm    Post subject: Re: Template M.P. -- why won't this work? Reply with quote

Graeme, Sorry for the syntax errors from the code posted my email. I
compiled and tested everything and got no VC7.1 errors or warnings and
it ran fine. I admit my cut and paste ignored include files and using
namespace std.


// Carlos code which locks up VC7.1
// metaloop<N,M>::pass<X+1,T>::go();

I agree infinite recursion may be not be the correct semantics.
Maybe I should say infinite loop, As the template instantion
progresses, N never changes and each succesive template instantiation
uses the same N, Therefore N never reaches M and an "infinite loop"
occurs. I checked this out with my VC7.1 debugger. But when I use:

// no lock up if change Carlos code to
// metaloop<N+1,M>::pass<X+1,T>::go();

As the template instantiation progresses , N -> N+1 ->N+2
............->M, so no infinite loop occurs. Thank you.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.