C ++ std :: variable - набирает признаки, чтобы убедиться, что содержащиеся типы вариантов соответствуют некоторым предположениям - PullRequest
5 голосов
/ 03 ноября 2019

Допустим, у меня есть некоторый набор типов, у всех из которых есть общий родительский элемент:

struct some_tag;

struct A : some_tag;
struct B : some_tag;
struct C : some_tag;
struct D : some_tag;

По отдельности можно проверить, является ли тип дочерним для some_tag с:

template <typename T>
using has_some_tag = std::is_base_of<some_tag, T>;

Но, скажем, у меня есть несколько вариантов, которые могут принимать любое число и любую комбинацию этих типов, например:

using variant_1 = std::variant<A,B,C>;
using variant_2 = std::variant<B,C>;
using variant_3 = std::variant<D,A>;
...

А затем, скажем, я использую эти типы вариантов для передачив качестве параметра шаблона для некоторого класса, который имеет логику посещений для работы с каждым из типов.

template <typename V>
struct some_other_type;

Для типа V мне бы хотелось иметь static_assertions, чтобы он соответствовал следующим критериям:

  1. V - это вариант
  2. V - это вариант, который принимает ТОЛЬКО типы, наследуемые от some_tag.

Я думаю, что яСоберите все мелкие кусочки вместе, но я не могу найти лучший способ проверить тип варианта.

Я думаю, что мне нужна черта, которая бы эффективно утверждала, что конкретная черта сохраняется для каждого базового типа. Я должен отметить, что ЕДИНСТВЕННОЕ предположение, которое можно сделать здесь, это V, должно содержать только то, что наследуется от some_tag, но мы не можем делать предположения о порядке или количестве вещей, которые это влечет за собой.

Есть указатели?

1 Ответ

5 голосов
/ 03 ноября 2019

Вы можете использовать частичную специализацию:

template<class>
struct checker : std::false_type {};

template<class... Ts> 
struct checker<std::variant<Ts...>> : 
    std::bool_constant<(has_some_tag<Ts>::value && ...)> {};

и затем написать:

template<typename V>
struct some_other_type {
    static_assert(checker<V>::value);
};

В качестве альтернативы, вы можете использовать std::conjunction вместо && сгиба:

template<class... Ts> 
struct checker<std::variant<Ts...>> : std::conjunction<has_some_tag<Ts>...> {};

Правка. std::integral_constant<bool> заменено на std::bool_constant. Спасибо, max66 .

...