I have a class with an std::variant
in it. This std::variant
type is only allowed to hold a specific list of types.
I have template functions which allow the user of the class to insert various values into an std::unordered_map
, the map holds values of this variant type. I.e., the user is only allowed to insert values if it's type is in the specific list of types. However, I don't want the user to be able to define this list of types themselves.
class GLCapabilities { public: using VariantType = std::variant<GLint64>; // in future this would have other types template <typename T> std::enable_if_t<???> AddCapability(const GLenum parameterName) { if(m_capabilities.count(parameterName) == 0) { /*... get correct value of type T ... */ m_capabilities.insert(parameterName,value); } } template<typename T> std::enable_if_t<???,T> GetCapability(const GLenum parameterName) const { auto itr = m_capabilities.find(parameterName); if(std::holds_alternative<T>(*itr)) return std::get<T>(*itr); return T; } private: std::unordered_map<GLenum,VariantType> m_capabilities; };
You'll see in the above where there's the ???
, how can I check? Some combination of std::disjunction
with std::is_same
?
Like
std::enable_if<std::disjunction<std::is_same<T,/*Variant Types???*/>...>>
To make it clear, I'd prefer to not have to check against each allowed type manually.
According to cppreference ::std::variant must not allocate dynamic memory.
Since this function is specific to a given type, you don't need RTTI to perform the operations required by std::any .
std::variant (C++17)An instance of std::variant has a value from one of its types. The value must not be a reference, C-array or void. A std::variant can have one type more than once. A default-initialized std::variant will be initialized with its first type.
Edit: I actually dig your std::disjunction
idea, and it absolutely works. You just have to extract the type list using template specialization.
My entire old-school recursive mess becomes simply:
template<typename T, typename VARIANT_T> struct isVariantMember; template<typename T, typename... ALL_T> struct isVariantMember<T, std::variant<ALL_T...>> : public std::disjunction<std::is_same<T, ALL_T>...> {};
Original answer: Here's a simple template that accomplishes this. It works by returning false
for empty type lists. For non-empty lists, it returns true
if the first type passes std::is_same<>
, and recursively invokes itself with all but the first type otherwise.
#include <vector> #include <tuple> #include <variant> // Main lookup logic of looking up a type in a list. template<typename T, typename... ALL_T> struct isOneOf : public std::false_type {}; template<typename T, typename FRONT_T, typename... REST_T> struct isOneOf<T, FRONT_T, REST_T...> : public std::conditional< std::is_same<T, FRONT_T>::value, std::true_type, isOneOf<T, REST_T...> >::type {}; // Convenience wrapper for std::variant<>. template<typename T, typename VARIANT_T> struct isVariantMember; template<typename T, typename... ALL_T> struct isVariantMember<T, std::variant<ALL_T...>> : public isOneOf<T, ALL_T...> {}; // Example: int main() { using var_t = std::variant<int, float>; bool x = isVariantMember<int, var_t>::value; // x == true bool y = isVariantMember<double, var_t>::value; // y == false return 0; }
N.B. Make sure you strip cv and reference qualifiers from T before invoking this (or add the stripping to the template itself). It depends on your needs, really.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With