Search code examples
c++templatestmp

Enabling certain template parameters based on user provided template arguments


Consider the following class template:

template<class T, std::size_t S, SomeEnum = SomeEnum::NOT_DYNAMIC>
class Foo {

Where SomeEnum would be defined as

class SomeEnum { NOT_DYNAMIC, DYNAMIC };

This class has a private std::array, but based on the value passed by the user to SomeEnum, I would like to instead use std::vector. For example, if the user passes SomeEnum::DYNAMIC, I would use std::vector instead of std::array. This would be implemented through std::conditional_t and [[no_unique_address]].

I am wondering if there is a way to "remove" the non-type template parameter S, in case the user passed SomeEnum::DYNAMIC. This is to avoid having the user type a size, when it is unnecessary because the underlying contaier is std::vector. Meanwhile, I need to keep the S parameter in case the user does not pass anything to SomeEnum, because std::array requires the size too.

Is it possible with some trickery, and if not, how would I solve this?

Current thoughts:

  • Using std::conditional_t as explained,
  • Using inheritance, or using a specialization (not yet attempted or thought of)
  • Polymorphism is NOT an option

Solution

  • A similar situation in the standard library exists with std::span<T, N> or std::span<T>: Omitting the template parameter entirely defaults the size to std::dynamic_extent ((std::size_t) -1), which you can use to have a std::vector instead of a std::array:

    template<class T, std::size_t S = std::dynamic_extent>
    class Foo {
    private:
        std::conditional_t<(S == std::dynamic_extent), std::vector<T>, std::array<T, S>> container;
    };