C ++ std :: variant-类型特征以验证所包含的变量类型是否满足某些假设

时间:2019-11-03 18:40:50

标签: c++ templates c++17 variadic-templates typetraits

比方说,我有一些类型的集合都有共同的父代:

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 个答案:

答案 0 :(得分:5)

您可以使用部分专业化:

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