consider the following example of a compile-time "vector".
#include <iostream>
template <int n, int...ns>
struct static_vector {
static constexpr int value = n;
static_vector<ns...> rest;
};
template <int n>
struct static_vector<n> {
static constexpr int value = n;
void* rest;
};
template <int n, class sv>
constexpr int access_nth() {
static_assert(n >= 0, "vector size out of bound");
if constexpr(n == 0) {
return sv::value;
} else {
static_assert(!std::is_same_v<decltype(sv::rest), void *>, "vector size out of bound");
return access_nth<n-1, decltype(sv::rest)>();
}
}
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
constexpr int nth = access_nth<5, decltype(a)>();
std::cout << nth << std::endl;
}
I am mostly satisfied with what we can do now: define a vector and then get the nth element out of it. The one thing I found that not satisfying is this: I have to use void *
as a dummy in the base case (where the vector only holds one element and no tail...)
I tried to have a specialisation like this:
template <>
struct static_vector<> {
}
to represent the empty vector. But it seems that the compiler always rejects this definition with the following error:
<source>:16:8: error: too few template arguments for class template 'static_vector'
struct static_vector<> {
^
What should I do here so I can have an empty vector?
Thanks a lot.
But why recursion ?
You tagged C++17 so you can use template folding, so... what about as follows ?
#include <iostream>
template <int ... Is>
struct static_vector
{
template <std::size_t N>
int get () const
{
static_assert( N < sizeof...(Is), "index out of bound" );
std::size_t i{};
int ret;
( ... , (N == i++ ? ret = Is : 0) );
return ret;
}
};
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
std::cout << a.get<3u>() << std::endl;
}