static_assert一个类型在std :: variant的可接受类型之中

v.o*_*dou 1 c++ metaprogramming variant c++17

在C ++ 17中,如何验证constexpr类型是否属于变量的类型列表?

例如:

using MyVt = std::variant<int, float>;
static_assert( MyVt::has_type< bool >::value, "oops, forgot bool");
Run Code Online (Sandbox Code Playgroud)

要么

static_assert( mpl::has_key< MyVt::typelist, T >::value, "oops, forgot T");
Run Code Online (Sandbox Code Playgroud)

当然,在概念表达式或static_assert模板函数中更有用。限制接受的可能类型。

如果我们不能为此使用显式支持的标准元功能或金属主义者,则可以使用涉及构造函数表达式的SFINAE破解检查吗?

Jul*_*ius 5

The basic solution uses a fold expression (C++17) and partial specialization:

#include <type_traits>
#include <variant>

template<class T, class TypeList>
struct IsContainedIn;

template<class T, class... Ts>
struct IsContainedIn<T, std::variant<Ts...>>
  : std::bool_constant<(... || std::is_same<T, Ts>{})>
{};

using MyVt = std::variant<int, float>;
static_assert(IsContainedIn<bool, MyVt>::value, "oops, forgot bool");
Run Code Online (Sandbox Code Playgroud)

You can make it more generic by using a template template parameter. This way, it also works for std::tuple, std::pair, and other templates. Those other templates must use only type template parameters, though (e.g., std::array does not match the template template parameter template<class...> class Tmpl in the example below).

template<class T, template<class...> class Tmpl, class... Ts>
struct IsContainedIn<T, Tmpl<Ts...>>
  : std::bool_constant<(... || std::is_same<T, Ts>{})>
{};
Run Code Online (Sandbox Code Playgroud)

Finally, this good C++17 answer to a C++11 question uses std::disjunction instead of a fold expression. You can think of std::disjunction as the functional any_of. This enables short-circuit evaluation (at compile time). In this case it reads

template<class T, template<class...> class Tmpl, class... Ts>
struct IsContainedIn<T, Tmpl<Ts...>>
  : std::disjunction<std::is_same<T, Ts>...>
{};
Run Code Online (Sandbox Code Playgroud)

The cppreference notes on std::disjunction state that

[...]

The short-circuit instantiation differentiates disjunction from fold expressions: a fold expression like (... || Bs::value) instantiates every B in Bs, while std::disjunction_v<Bs...> stops instantiation once the value can be determined. This is particularly useful if the later type is expensive to instantiate or can cause a hard error when instantiated with the wrong type.