Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ std::variant - Type traits to verify that the contained variant types meet some assumptions

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:

  1. V is a variant
  2. V 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?

like image 785
NOP Avatar asked Nov 03 '19 18:11

NOP


People also ask

What is std :: variant in C++?

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).

What is C++ trait?

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.


1 Answers

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.

like image 131
Evg Avatar answered Sep 30 '22 00:09

Evg