6

Given a template like

template<int dim> class Point { ... };

this template can be instantiated explicitly like

template class Point<0>;
template class Point<1>;
template class Point<2>;
template class Point<3>;

instead of instantiating every template individually like above, I would like to instantiate them recursively with one call like

template class RecursiveInstantiate<Point, 3>;

where RecursiveInstantiate<T, i> would instantiate T<i>, T<i-1>, ..., T<0>. Is it somehow possible to create such a class RecursiveInstantiate? If it is not possible, do you know a way to do it with the preprocessor?

In fact I am interested in generalizing this for classes with multiple template parameters likeNode<int i1,int i2,int i3> for all combination of i1,i2,i3 in {0,1,2,3}. But I hope to be able to work out this second part by myself.

Any advice, also an explanation why it is impossible what I want to achieve is appreciated.


Update: thank you for your comments so far. I see now more clearly where the problem really is. The line

template class Point<3>;

instantiates the template and exports its symbols to the object file. An instantiation of the form

template class RecursiveInstantiate<Point, 3>;

may instantiate the classes class Point<3>, class Point<2>, .... Apparently this only happens locally though. The templates are not exported to the object file. Maybe I will have to look for a solution using the preprocessor.

As I see now that I did not ask my question precisely enough in the beginning, I appreciate your answers and selected ones as correct.

Note: I am trying this on linux with g++/clang as compilers.

H. Brandsmeier
  • 917
  • 4
  • 19

2 Answers2

9

You could make a little Instantiator class:

template <unsigned int N> struct Instantiator
{
  Point<N> p;
  Instantiator<N-1> i;
};

template <> struct Instantiator<0>
{
  Point<0> p;
};

Then simply add one explicit instantiation: template struct Instantiator<81>;

You can extend this idea lexicographically to any number of integral parameters.


As @Georg says, let's make it generic:

template <template <unsigned int> class T, unsigned int N> struct Instantiator
{
  T<N> t;
  Instantiator<T, N-1> i;
};

template <template <unsigned int> class T> struct Instantiator<T, 0>
{
  T<0> t;
};

template struct Instantiator<Point, 82>;
Kerrek SB
  • 428,875
  • 83
  • 813
  • 1,025
  • Make it `template struct I { T p; I; }; ...`. Also, using meta-algorithms & meta-functions would avoid hard-coding parameter counts (see what Boost.MPL does). – Georg Fritzsche Sep 12 '11 at 23:23
  • This solution looks very nice, I really like your generic solution. I still have struggles getting this to work. The approach compiles nicely, yes, but somehow the symbols for `Point<0>` are not exported into the object file, which is what the code `template class Point<0>;` would be doing. I will have to investigate this further tomorrow. I am using g++/clang on Linux, but I'm not sure if this is specific to my architecture. – H. Brandsmeier Sep 13 '11 at 00:00
  • I'm not sure this actually works. No variation of this that I've tried actually produces anything in an object file. – Barry Oct 12 '15 at 16:31
4

You can do that like this:

template<int dim> struct Point {
    static const int val = dim;
    Point<dim - 1> p;
};

template<> struct Point<0> { ... };

That creates a template specialisation for the template parameter when it is 0 so the recursion stops there, and when you instantiate one like this:

Point<4>

It instantiates from Point<4> down to Point<0>. Then you can do

Point<4>::val

to access the value of that particular one.

Seth Carnegie
  • 70,115
  • 19
  • 169
  • 239
  • 3
    That requires modifying and having control over the definition of `Point`, though. – Kerrek SB Sep 12 '11 at 23:20
  • @Kerrek the concept can easily be extended to be used without modifying `Point`. – Seth Carnegie Sep 12 '11 at 23:21
  • This approach did not work for me. If I instantiate `template class Point<4>;` then only the symbols for `Point<4>` get exported into the object file, not the other symbols, although indeed the recursion is correctly executed by the compiler. – H. Brandsmeier Sep 13 '11 at 07:40