Search code examples
c++templatesc++17variadic-templatestemplate-meta-programming

Represents empty type in C++ class template


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.


Solution

  • 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;
     }