darius - 1 year ago 50

C++ Question

The

`#if`

In practice, I have something like this:

`template<int i>`

class Elem{ /*...*/};

#ifndef NUM_ELEM

#define NUM_ELEM 2

#endif

class MyClass

{

#if NUM_ELEM >= 1

Elem<1> e_1;

#endif

#if NUM_ELEM >= 2

Elem<2> e_2;

#endif

#if NUM_ELEM >= 3

Elem<3> e_3;

#endif

/*...*/

}

But I'd really like to make MyClass into a template itself:

`template<int num_elem>`

MyClass{

#if num_elem >= 1 //but #if can't understand num_elem

Elem<1> e_1;

#endif

#if num_elem >= 2

Elem<2> e_2;

#endif

#if num_elem >= 3

Elem<3> e_3;

#endif

/*...*/

};

Answer Source

The short answer is no, but if you're willing to change your requirements a little, you could do something like:

```
// A run of elements - Elem<n>, ..., Elem<2>, Elem<1>
template <int n> class NumElems
{
template <int u, int v> friend class ElemGetter;
NumElems<n-1> before;
public:
Elem<n> e;
// method to retrieve an element by number
template <int m> Elem<m> &getElem();
};
// helper class to retrieve an element.
// 'n' is the element number to retrieve
// 'm' is the number of elements
// by default, ElemGetter<n,m> defers to ElemGetter<n,m-1>.
template <int n, int m> class ElemGetter
{
public:
static Elem<n> &getElem(NumElems<m> &numElems)
{
return ElemGetter<n,m-1>::getElem(numElems.before);
}
};
// specialisation of ElemGetter: if the element to get is the same as the
// number of elements (i.e. is the last element) then return it
// immediately.
template <int n> class ElemGetter<n,n>
{
public:
static Elem<n> &getElem(NumElems<n> &numElems)
{
return numElems.e;
}
};
// get an element by number; defers to the ElemGetter helper.
template <int n> template <int m> Elem<m> &NumElems<n>::getElem()
{
return ElemGetter<m,n>::getElem(*this);
}
template <> class NumElems<0>
{
};
```

... then you can declare your Elem member set with:

```
NumElems<NUM_ELEM> elems;
```

And you can access them by using:

```
Elem<2> &e = elems.getElem<2>();
```

**Original proposed code**

The original code I proposed does not actually compile, but I'll include it here as it better demonstrates *intent* of the above:

```
// Original, doesn't compile - but it would be nice if it did :/
template <int n> class NumElems : private NumElems<n-1>
{
Elem<n> e;
template <int m> Elem<m> &getElem()
{
return NumElems<n-1>::getElem<m>();
}
template <> Elem<n> &getElem<n>()
{
return e;
}
};
template <> class NumElems<0>
{
};
```

Unfortunately, C++ does not allow specialisation of member template functions in this way, though it's not clear (to me) why not - the code is definitely simpler without having to create a helper class, as in the working code above.