472,958 Members | 2,258 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,958 software developers and data experts.

Template metaprogramming: list of types and recursive templates

I am trying to teach myself template metaprogramming and I have been
trying to create lists of related types. I am however stuck when I want
to make a template that gives me the last type in a list. I started by
using a linked list of types with templates like:

struct MyClass1 {};
struct MyClass2 {};
struct MyClass3 {};

struct NullType {};

template <typename T>
struct Link {
typedef NullType next_type;
};

template <>
struct Link<MyClass1{
typedef MyClass2 next_type;
};

template <>
struct Link<MyClass2{
typedef MyClass3 next_type;
};

etc.

I have also devised a simple template to check if a particular template
has a next type or not:

template <typename T>
struct IsNullType {
enum { value = false };
};
template <>
struct IsNullType<NullType{
enum { value = true };
};

template <typename T>
struct HasNext
{
typedef typename Link<T>::next_type next;
enum { value = !IsNullType<next>::value };
};

Next I wanted to make a template that will give me the last element in
the list, i.e
Last<MyClass1>::type would be a typedef for MyClass3 in the example
above. What I am looking for is something equivalent to the following
pseudo-code:

type Last(input_type) {
if (has_next(input_type)) return Last(input_type->next);
else return input_type;
}

This suggests the need for recursive templates. Unfortunately, I can't
seem to get the syntax right. Can anybody point me back in the right
direction? I am aware that there are libraries that have already solved
this, like the Boost mpl, but I am more interested in the general
techniques involved to tackle something like this than a recommendation
of which library to use to solve this particular problem. Any help will
be greatly appreciated.

best regards Mark

Jul 2 '06 #1
5 3313
In article <11**********************@v61g2000cwv.googlegroups .com>,
"Mark Stijnman" <Ma***********@gmail.comwrote:
I am trying to teach myself template metaprogramming and I have been
trying to create lists of related types. I am however stuck when I want
to make a template that gives me the last type in a list. I started by
using a linked list of types with templates like:

struct MyClass1 {};
struct MyClass2 {};
struct MyClass3 {};

struct NullType {};

template <typename T>
struct Link {
typedef NullType next_type;
};

template <>
struct Link<MyClass1{
typedef MyClass2 next_type;
};

template <>
struct Link<MyClass2{
typedef MyClass3 next_type;
};

etc.

I have also devised a simple template to check if a particular template
has a next type or not:

template <typename T>
struct IsNullType {
enum { value = false };
};
template <>
struct IsNullType<NullType{
enum { value = true };
};

template <typename T>
struct HasNext
{
typedef typename Link<T>::next_type next;
enum { value = !IsNullType<next>::value };
};

Next I wanted to make a template that will give me the last element in
the list, i.e
Last<MyClass1>::type would be a typedef for MyClass3 in the example
above. What I am looking for is something equivalent to the following
pseudo-code:

type Last(input_type) {
if (has_next(input_type)) return Last(input_type->next);
else return input_type;
}

This suggests the need for recursive templates. Unfortunately, I can't
seem to get the syntax right. Can anybody point me back in the right
direction? I am aware that there are libraries that have already solved
this, like the Boost mpl, but I am more interested in the general
techniques involved to tackle something like this than a recommendation
of which library to use to solve this particular problem. Any help will
be greatly appreciated.
Maybe something along the lines of:

template <class T, bool = HasNext<T>::value>
struct Last
{
typedef Link<T>::next_type;
};

template <class T>
struct Last<T, false>
{
typedef T next_type;
};

However I see no way to program First. The problem is that given a
Link<T>, there is only a way to find the next_type, and not this type.
You might try including someting along the lines of:

template <typename T>
struct Link {
typedef T this_type;
typedef NullType next_type;
};

-Howard
Jul 2 '06 #2

Howard Hinnant wrote:
Maybe something along the lines of:

template <class T, bool = HasNext<T>::value>
struct Last
{
typedef Link<T>::next_type;
};

template <class T>
struct Last<T, false>
{
typedef T next_type;
};
Thanks, but unfortunately, that will only give you the next type in the
list if there is any, or the type itself if there is not. It will not
recursively traverse the whole list until the end. I've tried several
variants that all boil down to something along the lines of:

template <typename T>
struct Last
{
typedef If<HasNext<T>::value, Last<Link<T>::next_type>::type,
T>::type type;
};

using a standard If<bool, typename Ta, typename Tbtemplate, but this
gives all sorts of compile errors, most of which seem to have to do
with the fact that I use Last<T>::type before I have actually completed
defining it. So more specifically, I am looking for a way around this.
>
However I see no way to program First. The problem is that given a
Link<T>, there is only a way to find the next_type, and not this type.
You might try including someting along the lines of:

template <typename T>
struct Link {
typedef T this_type;
typedef NullType next_type;
};

-Howard
For now, I do not have a requirement to find the first element in the
list from a random link. But if I would, I would indeed need to
redefine the Link template. The list of types I have defined is
basically the equivalent of a singly linked list. "First" would require
one to define a doubly linked list. It would still require me to define
a recursive template. But as said, I have no need for it as yet.

Jul 4 '06 #3
Mark Stijnman wrote:
Howard Hinnant wrote:
>>Maybe something along the lines of:

template <class T, bool = HasNext<T>::value>
struct Last
{
typedef Link<T>::next_type;
};

template <class T>
struct Last<T, false>
{
typedef T next_type;
};


Thanks, but unfortunately, that will only give you the next type in the
list if there is any, or the type itself if there is not. It will not
recursively traverse the whole list until the end. I've tried several
variants that all boil down to something along the lines of:

template <typename T>
struct Last
{
typedef If<HasNext<T>::value, Last<Link<T>::next_type>::type,
T>::type type;
};

using a standard If<bool, typename Ta, typename Tbtemplate, but this
gives all sorts of compile errors, most of which seem to have to do
with the fact that I use Last<T>::type before I have actually completed
defining it. So more specifically, I am looking for a way around this.
In your Last template, note that the Last recursion is instantiated even
if the If chooses the other branch, so you have an infinite recursion I
think. To get around that, you can introduce delayed instantiation:

template <typename T>
struct Identity
{
typedef T type;
};

template <typename T>
struct Last
{
typedef typename If<
HasNext<T>::value,
Identity<T>,
Last<typename Link<T>::next_type>
>::type::type type;
};

Tom
Jul 5 '06 #4
Tom Widmer wrote:
template <typename T>
struct Last
{
typedef typename If<
HasNext<T>::value,
Identity<T>,
Last<typename Link<T>::next_type>
>::type::type type;
};
Whoops, I got the If backwards. Should be:

template <typename T>
struct Last
{
typedef typename If<
HasNext<T>::value,
Last<typename Link<T>::next_type>,
Identity<T>
>::type::type type;
};

Tom
Jul 5 '06 #5
>
Whoops, I got the If backwards. Should be:

template <typename T>
struct Last
{
typedef typename If<
HasNext<T>::value,
Last<typename Link<T>::next_type>,
Identity<T>
>::type::type type;
};

Tom
Thanks, this was quite enlightning. I had already realized at some
point that the none-chosen branch was also instantized, had forgotten
about it by the time I posted my original post, and realized it again
yesterday, but I would never have come up with the idea to circumvent
it by using this delayed evaluation trick. Many thanks for pointing
this one out, I'm sure it will come in handy in other circumstances as
well :)

I also found a different solution yesterday. I planned to post it, so
people with similar questions will be able to find more through google
than I did. I just hadn't gotten around to do that yet, so I'll do it
now. My solution also solves it by stopping the recursion on the
not-taken branch (when HasNext is false), but I did it by defining a
template specialization for Last on NullType:

template <typename T>
struct Last {
typedef typename Link<T>::next_type next;
typedef typename Last<next>::type last;
typedef typename If<HasNext<T>::value, last, T>::type type;
};

template <>
struct Last<NullType{
typedef NullType type;
};

Note that I split up the nested templates into smaller steps, it seems
my compiler likes that better (g++ 3.3 and 4.0) - or I am just not
understanding all of templates syntax yet, which is also highly
possible ;) At any rate, I don't think that this solution is any worse
or better than the solution given by Tom Widmer.

Jul 5 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
by: Dave | last post by:
Would people agree with the statement that to a large degree, using template metaprogramming techniques turns a C++ compiler into a C++ interpreter (but just for the metaprogrammed portions of the...
5
by: Mohammad | last post by:
Hi, Is it possible to disable a method of a template class depending on the typename at compile time? thanks!
6
by: Hendrik Schober | last post by:
Hi, I have a problem with extending some existing code. In a simplified form, the problem looks like this: I have four types, A, B, C, and D. Each A refers to zero, one, or more B's and each...
6
by: Neal | last post by:
Hi All, I used an article on XSLT and XML and creating a TOC written on the MSDN CodeCorner. ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/dncodecorn/html/corner042699.htm However, it did'nt...
7
by: Joe | last post by:
Hi, I found a concept named template metaprogramming that can be used in C+ + code at compile-time. I am a beginner at C++. But I am a programmer on the .NET platform. Do you know if template...
4
by: Alan Woodland | last post by:
I've been trying out more template metaprogramming ideas with typelists (mostly for personal learning, I'm aware boost most probably provides this facility already), and I've run into this small...
3
by: stdlib99 | last post by:
Hi, I have a simple question regarding templates and meta programming. I am going to try and work my way through the C++ Template Metaprogramming, a book by David Abrahams and Aleksey...
6
by: Gaijinco | last post by:
I'm trying to do a template class Node. My node.hpp is: #ifndef _NODE_HPP_ #define _NODE_HPP_ namespace com { namespace mnya { namespace carlos { template <typename T>
12
by: nooneinparticular314159 | last post by:
Hello. If I declare the following: template<int a, int b, int SomeArray> class DoSomething{ public: .. .. ..
0
tracyyun
by: tracyyun | last post by:
Hello everyone, I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
1
by: Teri B | last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course. 0ne-to-many. One course many roles. Then I created a report based on the Course form and...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
3
by: nia12 | last post by:
Hi there, I am very new to Access so apologies if any of this is obvious/not clear. I am creating a data collection tool for health care employees to complete. It consists of a number of...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
2
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.