Search code examples
c++templatesc++17sfinaeclass-template

Passing template parameter pack to type_traits and std::enable_if


I am trying to create a class holding std::variant with a member function that would only accept types held by the nested variant object.

That function works basically the same way as variant's operator=. However, the question is - how do I use std::enable_if and type_traits together with template parameter pack?

The example below (attempting to check if any of the Types is contractible from T) obviously doesn't compile:

template<typename... Types>
class Wrapper
{
public:
    template<typename T, std::enable_if_t<std::is_constructible_v<Types..., T>, bool> = true>
    void Set(const T& data) {
        m_data = data;
    }

private:
    std::variant<Types...> m_data;
};

int main()
{
    Wrapper<int, float> wrapper;
    wrapper.Set(123);
    return 0;
}

Solution

  • How do I use std::enable_if and type_traits together with template parameter pack?

    You might do as follows:

    #include <type_traits>
    
    template<typename T, typename... Types>
    inline constexpr bool areAllowedTypes = (std::is_constructible_v<T, Types> && ...);
    // && -> if all the types must be convertable, otherwise use ||
    

    now

    template<typename T>
    auto Set(const T& data) ->std::enable_if_t<areAllowedTypes<T, Types...>>
    {
        m_data = data;
    }
    

    Or since you have compiler support, using if constexpr

    template<typename T>
    void Set(const T& data)
    {
        if constexpr (areAllowedTypes<T, Types...>)  m_data = data;
    }