Variable length template arguments list?
Asked Answered
P

4

10

I remember seing something like this being done:

template <ListOfTypenames>
class X : public ListOfTypenames {};

that is, X inherits from a variable length list of typenames passed as the template arguments. This code is hypothetical, of course.

I can't find any reference for this, though. Is it possible? Is it C++0x?

Parahydrogen answered 2/10, 2009 at 20:3 Comment(0)
M
24

You can do it in current C++. You give the template a "large enough" number of parameters, and you give them defaults:

class nothing1 {};
class nothing2 {};
class nothing3 {};

template <class T1 = nothing1, class T2 = nothing2, class T3 = nothing3>
class X : public T1, public T2, public T3 {};

Or you can get more sophisticated and use recursion. First you forward-declare the template:

class nothing {};

template <class T1 = nothing, class T2 = nothing, class T3 = nothing>
class X;

Then you specialise for the case where all the parameters are default:

template <>
class X<nothing, nothing, nothing> {};

Then you properly define the general template (which previously you've only forward-declared):

template <class T1, class T2, class T3>
class X : public T1, public X<T2, T3>

Notice how in the base class, you inherit X but you miss the first parameter. So they all slide along one place. Eventually they will all be defaults, and the specialization will kick in, which doesn't inherit anything, thus terminating the recursion.

Update: just had a strange feeling I'd posted something like this before, and guess what...

Mccullers answered 2/10, 2009 at 20:6 Comment(7)
you could also use just one "nothing" classPenmanship
@Penmanship - I use use just one "nothing" class in the recursive version. You can't use the same class for the defaults in the non-recursive version, because you'll get "nothing is already a direct base class" errors.Mccullers
I don't understand: why do you skip the first parameter when inheriting from X?Kerch
What would happen if X<T1, T2, T3> inherited X<T1, T2, T3>? Infinite depth! But by skipping the first parameter, it means that we inherit X<T2, T3, nothing>, which in turn inherits X<T3, nothing, nothing>, which in turn inherits X<nothing, nothing, nothing>. For that "all nothings" case, there's a specialisation that doesn't inherit anything, so it stops. BTW, in the last part of the recursive example I originally didn't put in any usage of T1, so I've added inheritance of it to make it consistent with the non-recursive example (otherwise it doesn't actually answer the question!)Mccullers
+1 nice, but unfortunately does not work for base types like: X<int>Kedgeree
@Kedgeree - easy enough to fix it for non-class types. In the general template, instead of directly inheriting T1, inherit W<T1> where W is a wrapper class, probably with a typedef member to let you get at the type parameter.Mccullers
@Daniel Earwicker - is there another trick which allows parameters of the same type? ex. X<int, int> gives error "base-class 'TWrap<T>' is already a base-class of 'X<T1,T2>'". I tried virtual inheritance, but this keeps only 1 copy of int.Kedgeree
P
20

Sounds like you are referring to C++0x Variadic Templates. You can also achieve the same effect using Alexandrescu's TypeList construct from Loki.

I believe the variadic template syntax in question would look like the following.

template <typename...T>
class X : public T... {};
Pressey answered 2/10, 2009 at 20:9 Comment(1)
If I'm not mistaken, you'll also need to unpack the type: public T... {};Tragicomedy
P
4

As others already answered, variadic templates are part of the next standard, but can be emulated in current C++. One convenient tool for this is to use the Boost.MPL library. In your code, you write a single template parameter (let's name it "Typelist"), and the users of your template wrap the typelist in an MPL sequence. Example:

#include "YourType.h"
#include "FooBarAndBaz.h"
#include <boost/mpl/vector.hpp>

YourType<boost::mpl::vector<Foo, Bar, Baz> > FooBarBaz;

In the implementation of "YourType", you can access the elements in Typelist with various metafunctions. For example, at_c<Typelist, N> is the Nth element of the list. As another example, the "X" class in your question could be written with inherit_linearly as:

//Warning: Untested
namespace bmpl = boost::mpl;
template<class Typelist>
class X : bmpl::inherit_linearly<Typelist, bmpl::inherit<bmpl::_1, bmpl::_2> >::type
{
...
};
Prostitution answered 2/10, 2009 at 20:37 Comment(0)
I
2

Variable number of templates is part of the next C++ standard. However, you can get a taste of it if you're using GCC (from version 4.3). Here's a list of available C++0x features in GCC. You're looking for Variadic Templates.

By the way, if you need a formal reference on how to achieve the inheritance mechanism as described by Earwicker, it's on the book C++ Templates.

Intracranial answered 2/10, 2009 at 20:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.