How do I check if an std::variant can hold a certain 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.
template <class T> struct type {};
template <class T> constexpr type<T> type_v{};
template <class T, class...Ts, template<class...> class Tp>
constexpr bool is_one_of(type<Tp<Ts...>>, type<T>) {
return (std::is_same_v<Ts, T> || ...);
}
Then use is_one_of(type_v<VariantType>, type_v<T>)
in the enable_if
.
Since you're already using C++17, fold-expressions make this easier:
template <class T, class U> struct is_one_of;
template <class T, class... Ts>
struct is_one_of<T, std::variant<Ts...>>
: std::bool_constant<(std::is_same_v<T, Ts> || ...)>
{ };
For added readability, you could add an alias in your class:
class GLCapabilities
{
public:
using VariantType = std::variant<GLint64>; // in future this would have other types
template <class T> using allowed = is_one_of<T, VariantType>;
template <typename T>
std::enable_if_t<allowed<T>{}> AddCapability(const GLenum parameterName)
{ ... }
};