Let's say I have some set of types that all have a common parent:
struct some_tag;
struct A : some_tag;
struct B : some_tag;
struct C : some_tag;
struct D : some_tag;
Individually, one can test whether a type is a child of some_tag
with:
template <typename T>
using has_some_tag = std::is_base_of<some_tag, T>;
But, let's say I have some variants which could accept any number and any combination of these types, such as:
using variant_1 = std::variant<A,B,C>;
using variant_2 = std::variant<B,C>;
using variant_3 = std::variant<D,A>;
...
And then, let's say I'm using these variant types to pass in as a template parameter to some class that has visitation logic to deal with each of the types.
template <typename V>
struct some_other_type;
For type V
, I'd like to have static_assertions in place that it meets the following criteria:
V
is a variantV
is a variant that ONLY accepts types that inherit from some_tag
.I think I have all the small pieces together, but I can't work out the best way to inspect variant type.
I think what I need is a trait that would effectively assert that a particular trait holds for each underlying types. I should point out that the ONLY assumption one can make here is V
should only contain things that inherit from some_tag
, but we can't make assumptions about the ordering or number of the things that this entails.
Any pointers?
The class template std::variant represents a type-safe union. An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value (this state is hard to achieve, see valueless_by_exception).
Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details". - Bjarne Stroustrup. Both C and C++ programmers should be familiar with limits. h , and float.
You can use partial specialization:
template<class>
struct checker : std::false_type {};
template<class... Ts>
struct checker<std::variant<Ts...>> :
std::bool_constant<(has_some_tag<Ts>::value && ...)> {};
and then write:
template<typename V>
struct some_other_type {
static_assert(checker<V>::value);
};
Alternatively, you can employ std::conjunction
instead of an &&
fold:
template<class... Ts>
struct checker<std::variant<Ts...>> : std::conjunction<has_some_tag<Ts>...> {};
Edit. std::integral_constant<bool>
was replaced with std::bool_constant
. Thanks, max66.
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