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 

Using operator-> for TMP recursion

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





PostPosted: Thu Sep 22, 2005 9:11 am    Post subject: Using operator-> for TMP recursion Reply with quote



I wonder whether somebody already thought about using operator-> to
implement TMP recursion, since nested template instantiation limits
don't seem to apply there. Here's a simple example:

// determine sum of natural numbers from 1 to N
template <int N, int S = 0>
struct Sum {
Sum<N-1, S+N> operator -> () const { return Sum<N-1, S+N>(); }
};

template <int S>
struct Sum<0, S> {
struct Result { int result() const { return S; } } result;
Result const * operator -> () const { return &result; }
};

int main()
{
std::cout << Sum<100>()->result() << std::endl; // prints 5050
return 0;
}

-- Niklas Matthies

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

Back to top
David Abrahams
Guest





PostPosted: Thu Sep 22, 2005 11:28 am    Post subject: Re: Using operator-> for TMP recursion Reply with quote



Niklas Matthies <usenet-nospam (AT) nmhq (DOT) net> writes:

Quote:
I wonder whether somebody already thought about using operator-> to
implement TMP recursion, since nested template instantiation limits
don't seem to apply there. Here's a simple example:

// determine sum of natural numbers from 1 to N
template <int N, int S = 0
struct Sum {
Sum () const { return Sum<N-1, S+N>(); }
};

template <int S
struct Sum<0, S> {
struct Result { int result() const { return S; } } result;
Result const * operator -> () const { return &result; }
};

int main()
{
std::cout << Sum<100>()->result() << std::endl; // prints 5050
return 0;
}

Very cute! Unfortunately, until we have decltype it isn't very
general: you can't compute new types this way unless you're prepared
to use them immediately in a runtime context.

Have you done any tests to see if it consumes fewer compiler resources,
or can do more computation before blowing up, than the usual methods?
I'd like to see those results!

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

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


Back to top
Niklas Matthies
Guest





PostPosted: Thu Sep 22, 2005 2:27 pm    Post subject: Re: Using operator-> for TMP recursion Reply with quote



On 2005-09-22 11:28, David Abrahams wrote:
Quote:
Niklas Matthies <usenet-nospam (AT) nmhq (DOT) net> writes:

I wonder whether somebody already thought about using operator-> to
implement TMP recursion, since nested template instantiation limits
don't seem to apply there. Here's a simple example:

// determine sum of natural numbers from 1 to N
template <int N, int S = 0
struct Sum {
Sum () const { return Sum<N-1, S+N>(); }
};

template <int S
struct Sum<0, S> {
struct Result { int result() const { return S; } } result;
Result const * operator -> () const { return &result; }
};

int main()
{
std::cout << Sum<100>()->result() << std::endl; // prints 5050
return 0;
}

Very cute! Unfortunately, until we have decltype it isn't very
general: you can't compute new types this way unless you're prepared
to use them immediately in a runtime context.

That's right. You also can't compute compile-time constants.
To be true, the above isn't really TMP at all, since the chain
of operator->() invocations, which means the actual iteration,
conceptually happens at runtime.

My original idea was indeed to use a typeof facility, and then
I tried to make as much of it as possible without it.

Quote:
Have you done any tests to see if it consumes fewer compiler resources,
or can do more computation before blowing up, than the usual methods?

Not really. Since the templates have still to be instantiated, I don't
think that it will make a significant difference in terms of resources.
My aim was mainly to get rid of the hard limit on instantiation depth.

-- Niklas Matthies

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


Back to top
Kodt
Guest





PostPosted: Thu Sep 22, 2005 2:28 pm    Post subject: Re: Using operator-> for TMP recursion Reply with quote

Quote:
Very cute! Unfortunately, until we have decltype it isn't very
general: you can't compute new types this way unless you're prepared
to use them immediately in a runtime context.

Have you done any tests to see if it consumes fewer compiler resources,
or can do more computation before blowing up, than the usual methods?
I'd like to see those results!

I compared this approach with a more common one,

template<int N, int S=0>
struct Sum
{
enum { value = Sum<N-1,S+N>::value };
};
template<int S>
struct Sum<0,S>
{
enum { value = S };
};

As we can see, both of them have linear recursion.
But operator-> makes a _tail_recursion_, so that compiler (Comeau Test
Drive) doesn't exceed its limits. And with my example, it does.

Pitily, the result of computation doesn't seem to be compile-time
constant. We cannot write

char buf[ Sum<100>()->value ];

even if it was defined
....
{
struct result { enum { value=S }; };
result* operator->() const { return NULL; }
}

----------
So, if we need a compile-time computations, we have to reduce the
algorithm's depth.
For instance,

template<int L, int C> // sum of [L..L+C) range
struct SumRange
{
enum { value = L +
SumRange<(L+1) ,(C-1)/2 >::value +
SumRange<(L+1)+(C-1)/2,(C-1)-(C-1)/2>::value
};
};
template<int L>
struct SumRange<L,0> // empty range
{
enum { value = 0 };
};
template<int N>
struct Sum
{
enum { value = SumRange<1,N>::value };
};


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


Back to top
Marco Jez
Guest





PostPosted: Thu Sep 22, 2005 5:39 pm    Post subject: Re: Using operator-> for TMP recursion Reply with quote

"Niklas Matthies" <usenet-nospam (AT) nmhq (DOT) net> ha scritto nel messaggio
news:slrndj41ri.23cd.usenet-nospam (AT) nmhq (DOT) net...
Quote:
I wonder whether somebody already thought about using operator-> to
implement TMP recursion, since nested template instantiation limits
don't seem to apply there. Here's a simple example:

Since you can only evaluate the result at run time (as opposite to usual TMP
recursion which takes place at compile time), what's the advantage of using
this code instead of a non-template function?

Marco



[ 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: Fri Sep 23, 2005 1:18 pm    Post subject: Re: Using operator-> for TMP recursion Reply with quote

Marco Jez wrote:
Quote:
"Niklas Matthies" <usenet-nospam (AT) nmhq (DOT) net> ha scritto nel messaggio
news:slrndj41ri.23cd.usenet-nospam (AT) nmhq (DOT) net...
I wonder whether somebody already thought about using operator-> to
implement TMP recursion, since nested template instantiation limits
don't seem to apply there. Here's a simple example:

Since you can only evaluate the result at run time (as opposite to usual TMP
recursion which takes place at compile time), what's the advantage of using
this code instead of a non-template function?

Marco

There's no requirement that the expression be evaluated only at
runtime. The requirement is that the result of the evaluation cannot be
used in an expression requiring a compile-time constant. But a
compile-time evaluation can be used productively in other ways.

As an example, an optimizing compiler with sufficient inline recursion
depth resolution will realize that that this expression:

Sum<100>()->result()

is a constant expression evaluating to 5050. The optimizer will replace
this expression with the value 5050 and not invoke the ->() operator at
all. And no, I am not speculating here. I know from compiling and
disassembling the original example that there is at least one C++
compiler (I tested Metrowerks) that performs this optimization today.

Greg


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


Back to top
Harald van Dijk
Guest





PostPosted: Fri Sep 23, 2005 1:20 pm    Post subject: Re: Using operator-> for TMP recursion Reply with quote

Niklas Matthies wrote:
Quote:
I wonder whether somebody already thought about using operator-> to
implement TMP recursion, since nested template instantiation limits
don't seem to apply there. Here's a simple example:

Very interesting. Here's a modified version:

#include <iostream>

template <int N, int S = 0>
struct Sum { Sum<N-1, S+N> operator->(); };

template <int S>
struct Sum<0, S> {
struct Result { char result[S]; };
Result *operator->();
};

int main() {
std::cout << sizeof(Sum<100>()->result) << std::endl;
}

Is this still valid? And if so, can sizeof(Sum<100>()->result) be used
as any other constant?


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


Back to top
David Abrahams
Guest





PostPosted: Sat Sep 24, 2005 2:09 am    Post subject: Re: Using operator-> for TMP recursion Reply with quote

Niklas Matthies <usenet-nospam (AT) nmhq (DOT) net> writes:

Quote:
Very cute! Unfortunately, until we have decltype it isn't very
general: you can't compute new types this way unless you're prepared
to use them immediately in a runtime context.

That's right. You also can't compute compile-time constants.
To be true, the above isn't really TMP at all, since the chain
of operator->() invocations, which means the actual iteration,
conceptually happens at runtime.

I don't know about that. The very first TMP was probably expression
templates, which look pretty runtime-ish in a very similar way.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

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


Back to top
Niklas Matthies
Guest





PostPosted: Sat Sep 24, 2005 2:21 am    Post subject: Re: Using operator-> for TMP recursion Reply with quote

On 2005-09-23 13:20, Harald van D?k wrote:
Quote:
Niklas Matthies wrote:
I wonder whether somebody already thought about using operator-> to
implement TMP recursion, since nested template instantiation limits
don't seem to apply there. Here's a simple example:

Very interesting. Here's a modified version:

#include <iostream

template struct Sum { Sum(); };

template <int S
struct Sum<0, S> {
struct Result { char result[S]; };
Result *operator->();
};

int main() {
std::cout << sizeof(Sum<100>()->result) << std::endl;
}

Very nice!

Quote:
Is this still valid? And if so, can sizeof(Sum<100>()->result) be
used as any other constant?

Yes and yes.

-- Niklas Matthies

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


Back to top
Przemyslaw Szymanski
Guest





PostPosted: Sat Sep 24, 2005 2:22 am    Post subject: Re: Using operator-> for TMP recursion Reply with quote

Out of sheer curiosity - what do you think about this modification of
that common implementation?

#include <iostream>

template <int N, int S = 0>
struct sum
{
typedef typename sum<N - 1, S + N>::type type;
};

template <int S>
struct sum<0, S>
{
typedef sum type;
enum { value = S };
};


int main()
{
int a = sum<100>::type::value;
std::cout << a << std::endl;
return 0;
}

Still limited by the template recursion depth, though...

Przemek.


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

Back to top
Niklas Matthies
Guest





PostPosted: Sun Sep 25, 2005 1:39 am    Post subject: Re: Using operator-> for TMP recursion Reply with quote

On 2005-09-24 02:09, David Abrahams wrote:
Quote:
Niklas Matthies <usenet-nospam (AT) nmhq (DOT) net> writes:

Very cute! Unfortunately, until we have decltype it isn't very
general: you can't compute new types this way unless you're prepared
to use them immediately in a runtime context.

That's right. You also can't compute compile-time constants.
To be true, the above isn't really TMP at all, since the chain
of operator->() invocations, which means the actual iteration,
conceptually happens at runtime.

I don't know about that. The very first TMP was probably expression
templates, which look pretty runtime-ish in a very similar way.

I guess you're right, since the generation of the invocation chain
is controlled by template logic.

On another note: Is there some intrinsic reason why compilers should
impose a fixed (if configurable) limit on the number of nested
template instantiations, while they don't on operator -> recursion?

-- Niklas Matthies

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


Back to top
David Abrahams
Guest





PostPosted: Mon Sep 26, 2005 8:30 am    Post subject: Re: Using operator-> for TMP recursion Reply with quote

Niklas Matthies <usenet-nospam (AT) nmhq (DOT) net> writes:

Quote:
On another note: Is there some intrinsic reason why compilers should
impose a fixed (if configurable) limit on the number of nested
template instantiations, while they don't on operator -> recursion?

The standard has a "recommended minimum" for the former; perhaps they
are trying to help you write portable code?

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

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


Back to top
Niklas Matthies
Guest





PostPosted: Tue Sep 27, 2005 11:29 am    Post subject: Re: Using operator-> for TMP recursion Reply with quote

On 2005-09-26 08:30, David Abrahams wrote:
Quote:
Niklas Matthies <usenet-nospam (AT) nmhq (DOT) net> writes:

On another note: Is there some intrinsic reason why compilers should
impose a fixed (if configurable) limit on the number of nested
template instantiations, while they don't on operator -> recursion?

The standard has a "recommended minimum" for the former;

Of course. To elaborate my question into a couple of related ones:

Since the standard doesn't bother to specify a recommended minimum
for the latter (and that doesn't seem to hurt), why does it for the
former?

Why is the specified recommended minimum so small compared to most
of the other recommended minima?

Why do compilers by default impose a pretty small limit; much smaller
than I would estimate the associated resource consumption to suggest?

Quote:
perhaps they are trying to help you write portable code?

Perhaps. But in practice it appears to have the effect of compilers
accepting less programs than they would otherwise (judging from how
they behave for operator -> recursion), while on the theoretical side
it doesn't make code more portable in the strict sense, since the
minimum is only "recommended", which means it still remains a QoI
issue. If we relate the "Q" to the number of supported nested levels,
then the specified minimum appears to have the effect of a much lower
"Q" for template recursion than for operator -> recursion.

-- Niklas Matthies

[ 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.