Zebrafish
Zebrafish

Reputation: 13936

How can I vary this template class to take an additional template parameter?

I'm having trouble having an extra template parameter to my class template. I'm not sure if this is possible but I think it's clear what I'm trying to do:

struct NullableType { };

template <typename value_t>
struct ArrayMap
{
    static inline constexpr bool bIsValueNullableType = std::is_base_of_v<NullableType, value_t>;
    std::vector<value_t> arr;
    void remove(const uint64 key) 
    { 
        if constexpr (bIsValueNullableType) arr[key].makeNull();
    }
    

};

// In this version I want to take an integer type for the first argument and a null value as the second
template <typename integral_t, integral_t null_v > 
struct ArrayMap
{
    void remove(const uint64 key) { arr[key] = null_v;}
};

In the version taking an integer type and a null integer value I want to rewrite at least little code as possible, hopefully only removing and checking a key will require adding new functions.

Upvotes: 1

Views: 54

Answers (1)

janekb04
janekb04

Reputation: 4925

As you haven't specified if you are limited to an old C++ standard I will propose a solution in C++20.

You can use template specialization. Your primary template will have to take two arguments (a type and a non type argument):

template <typename value_t = int, auto null_v = 0>
struct ArrayMap;

Then, a specialization for integral types can use the std::integral concept introduced in C++20. Otherwise you would have to use SFINAE (possibly an std::enable_if_t):

template <std::integral integral_t, integral_t null_v> 
struct ArrayMap<integral_t, null_v> 
{
    std::vector<integral_t> arr;
    void remove(const uint64_t key)
    { 
        arr[key] = null_v;
    }
};

Finally the specialization for non integral types can ignore the second argument:

template <typename value_t>
struct ArrayMap<value_t, 0>
{
    static inline constexpr bool bIsValueNullableType = std::is_base_of_v<NullableType, value_t>;
    std::vector<value_t> arr;
    void remove(const uint64_t key) 
    { 
        if constexpr (bIsValueNullableType) 
            arr[key].makeNull();
    }
};

As you can see there is a bit of code duplication. To deal with that, you could extract common functionality to a base class an inherit from it.

(godbolt)

Upvotes: 2

Related Questions