我有一个班里有一个std::variant.此std::variant类型仅允许保存特定的类型列表.
我有模板函数,允许类的用户插入各种值std::unordered_map,映射包含此变体类型的值.即,如果用户的类型在特定的类型列表中,则仅允许用户插入值.但是,我不希望用户能够自己定义这个类型列表.
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;
};
Run Code Online (Sandbox Code Playgroud)
你会在上面看到哪里有???,我怎么检查?一些组合std::disjunction与std::is_same?
喜欢
std::enable_if<std::disjunction<std::is_same<T,/*Variant Types???*/>...>>
Run Code Online (Sandbox Code Playgroud)
为清楚起见,我宁愿不必手动检查每个允许的类型.
Fra*_*ank 11
编辑:我实际上挖掘你的std::disjunction想法,它绝对有效.您只需使用模板专门化提取类型列表.
我整个老派的递归混乱变得简单:
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>...> {};
Run Code Online (Sandbox Code Playgroud)
原始答案:这是一个完成此任务的简单模板.它通过返回false空类型列表来工作.对于非空列表,true如果第一个类型通过则返回std::is_same<>,否则以除第一个类型之外的所有类型递归调用自身.
#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;
}
Run Code Online (Sandbox Code Playgroud)
注意确保在调用此方法之前从T中剥离cv和引用限定符(或将剥离添加到模板本身).这取决于你的需求,真的.
由于您已经在使用 C++17,折叠表达式使这变得更容易:
template <class T, class U> struct is_one_of;
template <class T, class... Ts>
struct is_one_of<T, std::variant<Ts...>>
: std::bool_constant<(std::is_same_v<T, Ts> || ...)>
{ };
Run Code Online (Sandbox Code Playgroud)
为了增加可读性,您可以在类中添加别名:
class GLCapabilities
{
public:
using VariantType = std::variant<GLint64>; // in future this would have other types
template <class T> using allowed = is_one_of<T, VariantType>;
template <typename T>
std::enable_if_t<allowed<T>{}> AddCapability(const GLenum parameterName)
{ ... }
};
Run Code Online (Sandbox Code Playgroud)
template <class T> struct type {};
template <class T> constexpr type<T> type_v{};
template <class T, class...Ts, template<class...> class Tp>
constexpr bool is_one_of(type<Tp<Ts...>>, type<T>) {
return (std::is_same_v<Ts, T> || ...);
}
Run Code Online (Sandbox Code Playgroud)
然后is_one_of(type_v<VariantType>, type_v<T>)在enable_if.