Home > Enterprise >  Using enable_if to decide the type of a member variable
Using enable_if to decide the type of a member variable

Time:06-14

template <typename ...T>
class BaseEvent
{
    BaseEvent(const unsigned int index, const uint8_t id, const std::variant<T...> data) : m_index(index), m_id(id), m_data(m_data){};
    virtual ~BaseEvent();

    template <typename V>
    const V get()
    {
        static_assert(constexpr std::is_same_v<V, T...>);
        return std::get<V>(m_data);
    };

protected:
    unsigned int m_index;
    uint8_t m_id;
    std::variant<T...> m_data;
    
    // pseudocode:
    // enable_if(sizeof(T...) > 1)
    // then: std::variant<T...> m_data
    // else: T m_data
};

However later in the code,

template <class T>
class StringEvent : public BaseEvent<T>
{
    virtual ~StringEvent();
    const T string() { return get<T>(); };
};

Pasing only a single type to BaseEvent will not be able to create variant as it is useless in that case anyways. How can I use enable_if to create m_data of type T when T... is a single type only?

CodePudding user response:

I have done exactly what you want to do, so I know what you need. To handle both single message and multiple message types, use std::variant<std::monostate, T...>. In addition, your use of is_same_v<> is incorrect. You can only use 1 type, not multiple types there.

So you need a code like this:

template <typename ...T>
class BaseEvent
{
    BaseEvent(const unsigned int index, const uint8_t id, const std::variant<T...> data) : m_index(index), m_id(id), m_data(m_data){}; 
    // ^-- There is a small bug here in creating variant(different types). you need to solve, and use in-place for variant.
    virtual ~BaseEvent();

    template <typename V>
    const V get()
    {
        static_assert(is_valid_type<V>() || std::is_same_v<V, std::monostate>);
        return std::get<V>(m_data);
    };

protected:
    unsigned int m_index;
    uint8_t m_id;
    std::variant<std::monostate, T...> m_data;

private:
    template<typename U>
    constexpr static bool is_valid_type() {
        return (std::is_same_v<U, T> || ...);
    }    
};

My main code is much more complex and I just extracted small part for this, so use it with care.

  • Related