如何检查std :: variant是否可以容纳某种类型 [英] How do I check if an std::variant can hold a certain type

查看:190
本文介绍了如何检查std :: variant是否可以容纳某种类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有 std :: variant 的类。此 std :: variant 类型只允许保存特定类型的列表。

I have a class with an std::variant in it. This std::variant type is only allowed to hold a specific list of types.

我有模板函数允许类的用户在 std :: unordered_map 中插入各种值,该映射将保留此变量类型的值。也就是说,仅当用户的类型在特定类型的列表中时,才允许用户插入值。但是,我不希望用户自己定义此类型列表。

I have template functions which allow the user of the class to insert various values into an std::unordered_map, the map holds values of this variant type. I.e., the user is only allowed to insert values if it's type is in the specific list of types. However, I don't want the user to be able to define this list of types themselves.

class GLCapabilities
{
public:
    using VariantType = std::variant<GLint64>;  // in future this would have other types

    template <typename T>
    std::enable_if_t<???> AddCapability(const GLenum parameterName)
    {
        if(m_capabilities.count(parameterName) == 0)
        {
            /*... get correct value of type T ... */
            m_capabilities.insert(parameterName,value);
        }
    }

    template<typename T>
    std::enable_if_t<???,T> GetCapability(const GLenum parameterName) const
    {
        auto itr = m_capabilities.find(parameterName);
        if(std::holds_alternative<T>(*itr))
            return std::get<T>(*itr);

        return T;
    }

private:
    std::unordered_map<GLenum,VariantType> m_capabilities;
};

您会在上面看到 ??? ,如何检查? std :: disjunction std :: is_same 的某种组合?

You'll see in the above where there's the ???, how can I check? Some combination of std::disjunction with std::is_same?

std::enable_if<std::disjunction<std::is_same<T,/*Variant Types???*/>...>>

为了明确起见,我希望不必手动检查每个允许的类型。 / p>

To make it clear, I'd prefer to not have to check against each allowed type manually.

推荐答案

编辑:我实际上是在挖掘您的 std :: disjunction 的想法,它绝对有效。您只需使用模板专业化就可以提取类型列表。

I actually dig your std::disjunction idea, and it absolutely works. You just have to extract the type list using template specialization.

我的整个老式递归混乱变得很简单:

My entire old-school recursive mess becomes simply:

template<typename T, typename VARIANT_T>
struct isVariantMember;

template<typename T, typename... ALL_T>
struct isVariantMember<T, std::variant<ALL_T...>> 
  : public std::disjunction<std::is_same<T, ALL_T>...> {};

原始答案:这是一个完成此任务的简单模板。通过为空类型列表返回 false 来工作。对于非空列表,如果第一个类型通过 std :: is_same<> ,则递归返回 true

Original answer: Here's a simple template that accomplishes this. It works by returning false for empty type lists. For non-empty lists, it returns true if the first type passes std::is_same<>, and recursively invokes itself with all but the first type otherwise.

#include <vector>
#include <tuple>
#include <variant>

// Main lookup logic of looking up a type in a list.
template<typename T, typename... ALL_T>
struct isOneOf : public std::false_type {};

template<typename T, typename FRONT_T, typename... REST_T>
struct isOneOf<T, FRONT_T, REST_T...> : public 
  std::conditional<
    std::is_same<T, FRONT_T>::value,
    std::true_type,
    isOneOf<T, REST_T...>
  >::type {};

// Convenience wrapper for std::variant<>.
template<typename T, typename VARIANT_T>
struct isVariantMember;

template<typename T, typename... ALL_T>
struct isVariantMember<T, std::variant<ALL_T...>> : public isOneOf<T, ALL_T...> {};

// Example:
int main() {
  using var_t = std::variant<int, float>;

  bool x = isVariantMember<int, var_t>::value; // x == true
  bool y = isVariantMember<double, var_t>::value; // y == false

  return 0;
}

确保在调用此之前从T剥离cv和reference限定词(或将剥离添加到模板本身)。确实取决于您的需求。

N.B. Make sure you strip cv and reference qualifiers from T before invoking this (or add the stripping to the template itself). It depends on your needs, really.

这篇关于如何检查std :: variant是否可以容纳某种类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆