Reputation: 3509
Suppose I want to instantiate many objects that come from a templated class (something like std::bitset) from bitset<1> to bitset<10>.
for (size_t i = 1; i <= 10; ++i) {
std::bitset<i> my_bitset;
// do stuff with it...
}
obviously this won't compile because i is not a literal or a constexpr
.
Is there a way to do this? I'm thinking everything template metaprogramming possible in my head but I can't figure this one out. Any pointers appreciated.
Upvotes: 1
Views: 299
Reputation: 98358
Something like (not tested):
template<int N>
struct InstantBS
{
std::bitset<N> bs;
InstantBS<N-1> next;
};
template<>
struct InstantBS<0>
{
};
template struct InstantBS<10>; //instantiate bitset<1> to bitset<10>
UPDATE: Well, I have tested it, and it does not work! The problem is that the members of InstantBS
are not implicitly instantiated. And unfortunately, explicit instantiation must occur at namespace level, so you cannot force a explicit instantiation from another explicit instantiation. Unfortunately, template namespaces are not invented yet...
The closest think I can devise is this, doing manual instantation of any member of the bitset
you need:
template<int N>
struct InstantBS
{
void DoThings()
{
std::bitset<N> bs;
bs.set();
bs.reset();
bs.flip();
//any other operation you want to instantiate
InstantBS<N-1> next;
next.DoThings();
}
};
template<>
struct InstantBS<0>
{
void DoThings()
{
}
};
template struct InstantBS<10>; //instantiate bitset<1> to bitset<10>, more or less
You can check that the requestet members of the bitsets are actually instantiated:
$ g++ -c test.cpp
$ objdump -t test.o | c++filt | grep bitset
Upvotes: 2
Reputation: 299820
It is not possible, as you realized, to use a runtime variable as a template parameter; however should you know the list of values to use at compile-time, then you can indeed have a way to invoke tests for each element of this list.
template <template <size_t> class F>
void run() {}
template <template <size_t> class F, size_t H, size_t... Tail>
void run() { F<H>()(); run<F, Tail...>(); }
Then it is just a matter of defining F
:
template <size_t N>
struct BitSetPlay {
void operator()() {
std::bitset<N> b;
b.flip();
std::cout << b.to_ulong() << "\n";
}
};
#include <bitset>
#include <iostream>
template <template <size_t> class F>
void run() {}
template <template <size_t> class F, size_t H, size_t... Tail>
void run() { F<H>()(); run<F, Tail...>(); }
template <size_t N>
struct BitSetPlay {
void operator()() {
std::bitset<N> b;
b.flip();
std::cout << b.to_ulong() << "\n";
}
};
int main() {
run<BitSetPlay, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u>();
return 0;
}
Note: this assumed a possibly discontiguous list, if it is a range you wish for then you can do without variadic templates by simply keeping track of the bounds.
Upvotes: 3
Reputation: 206
see docs: The size of a bitset is fixed at compile-time (determined by its template parameter). For a class that also optimizes for space allocation and allows for dynamic resizing, see the bool specialization of vector (vector).
Upvotes: 0
Reputation: 409176
It's not possible, because templates are a compile-time only concept. You can't use runtime data to declare templated instances.
Template arguments have to be types, or compile-time constants.
Upvotes: 2