Suppose, I have class with such definition:
template<unsigned int N>
class A { ... }
The question is how to iterate over this classes with N?
for(unsigned int i = 0; i < 10; ++i) {
A<i>().doStuff();
}
Maybe there is some new feature in C++ 11 or some cool using of contrexp .
And next question is: if it's possible - how to store such classes?
Update I know that it works at compile time. Suppose, I have up to 10 such global classes, which differs only in N. For example:
A<1> first;
A<2> second;
A<42> third;
A<1034> fourth;
And suppose, I should call the one who's got N bigger than my value. If there is no chances to iterate, so I have to write long if-else structure.
void doAppropriateStuff(int value) {
if (value < 1) {
first.doStuff();
} else if (value < 2) {
second.doStuff();
} else if (value < 42) {
third.doStuff();
} else if (value < 1034) {
fourth.doStuff();
} else {
...
}
}
Hope, the problem became clearer. As I googled that's impossible and I understand why. Only hopes on C++11 and SO community. Thanks.
It's obviously impossible with a for loop, because that's ran at runtime and template arguments need to be compile time constants. Here's how you could do it.
These are utility classes for constructing a sequence of integers as a template argument pack:
template< std::size_t... Ns >
struct indices {
typedef indices< Ns..., sizeof...( Ns ) > next;
};
template< std::size_t N >
struct make_indices {
typedef typename make_indices< N - 1 >::type::next type;
};
template<>
struct make_indices< 0 > {
typedef indices<> type;
};
The function that does the work:
#include <initializer_list>
template<size_t... Is>
void foo(indices<Is...>)
{
auto list = { (A<Is>().doStuff(), 0)... };
}
And you call the function like this:
foo(make_indices<10>::type());
If you do not want to rely on integer_sequence that is c++14, this is a simpler solution :
#include <iostream>
template<unsigned int N>
struct A {
void dostuff() const { std::cout << N << " "; }
};
template < int N > void run();
template <> void run<-1>() {}
template < int N > void run() {
run<N-1>();
A<N>{}.dostuff();
}
int main() {
run<10>();
}
EDIT : about your question update, you can do that if you store the objects inside a tuple, see here :
#include <iostream>
#include <tuple>
template<unsigned int N>
struct A {
unsigned int getN() const { return N; }
void dostuff() const { std::cout << N << " "; }
};
auto globals = std::make_tuple( A<3>{}, A<7>{}, A<10>{}, A<200>{} );
template <int idx> void run( int v );
template <> void run<std::tuple_size<decltype(globals)>::value>( int ) {}
template <int idx = 0> void run( int v ) {
auto & a = std::get<idx>(globals);
if ( v < a.getN() ) {
a.dostuff();
} else {
run<idx+1>(v);
}
}
int main() {
for( int i = 0; i<20; ++i)
run( i );
}
You would use template specialization:
template <unsigned int N> struct ADoer
{
static void go() { A<N>().doStuff(); ADoer<N - 1>::go(); }
};
template <> struct ADoer<0>
{
static void go() { }
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With