Home > Software engineering >  Require certain specialization of template as a template parameter
Require certain specialization of template as a template parameter

Time:07-21

I have a datastructure meta_array which is instantiated with a variant as type T parameter. The requirement is that the std::variant specialization must contain the type meta_array_head_t as this is is used for tracking information. Can I somehow state this as a requirement using type traits (C 17)?

CompilerExplorer:

#include <cstdio>
#include <variant>
#include <array>

struct meta_array_head_t {
    // end_;
    // remaining_;
    // prev_;
};

template <typename T, size_t S> // make sure T = std::variant<... , meta_array_head_t, ...>
struct meta_array
{
    std::array<T, S> data_; 
};


using val = std::variant<std::monostate, int, double, meta_array_head_t>;

int main()
{
    meta_array<val, 100> marray;
}

CodePudding user response:

First, determine that T is of type std::variant, then use fold expression to detect whether the alternative type contains meta_array_head_t.

#include <variant>

template<typename T>
struct meta_variant : std::false_type { };

template<typename... Ts>
struct meta_variant<std::variant<Ts...>> : 
  std::bool_constant<((std::is_same_v<Ts, meta_array_head_t> || ...))> { };

template <typename T, size_t>
struct meta_array {
  static_assert(meta_variant<T>::value, 
    "T must be a std::variant specialization "
    "containing an alternative type of meta_array_head_t.");
};

Demo

CodePudding user response:

Use std::disjunction_v instead of fold expression for short-circuiting.

Based on @康桓瑋's answer.

template<typename T>
struct meta_variant : std::false_type { };

template<typename... Ts>
struct meta_variant<std::variant<Ts...>> {
      static constexpr bool value = std::disjunction_v<std::is_same<Ts, meta_array_head_t>...>;
};

Demo

CodePudding user response:

You can use specialization to write the trait. Rather than allowing the user to make the mistake and only produce an error you could add the type to the variant when it isnt present:

#include <iostream>
#include <type_traits>
#include <variant>

struct foo {};

template <typename T>
struct has_foo_as_variant : std::false_type {};

template <typename... Ts>
struct has_foo_as_variant<std::variant<Ts...>> {
    static constexpr bool value = (std::is_same_v<Ts,foo> || ...);
};

template <typename T>
constexpr bool has_foo_as_variant_v = has_foo_as_variant<T>::value;

template <typename T>
struct variant_with_foo;

template <typename...Ts>
struct variant_with_foo< std::variant<Ts...>> {
    using type = std::conditional_t< has_foo_as_variant_v<std::variant<Ts...>>,
                                    std::variant<Ts...>,
                                    std::variant<foo,Ts...>>;
};

int main() {
    using good_t = std::variant<foo,int,double>;
    using bad_t = std::variant<int,double>;
    std::cout << has_foo_as_variant_v<good_t>;
    std::cout << has_foo_as_variant_v<bad_t>;
    using foo_added_t = typename variant_with_foo<bad_t>::type;
    std::cout << has_foo_as_variant_v<foo_added_t>;
}
  • Related