C++ 检查一组类型是否是另一组类型的子集
如何检查一个参数包(解释为一个集合)是否是另一个参数包的子集 到目前为止,我只有框架(使用std::tuple),但没有任何功能C++ 检查一组类型是否是另一组类型的子集,c++,c++11,templates,variadic-templates,template-meta-programming,C++,C++11,Templates,Variadic Templates,Template Meta Programming,如何检查一个参数包(解释为一个集合)是否是另一个参数包的子集 到目前为止,我只有框架(使用std::tuple),但没有任何功能 #include <tuple> #include <type_traits> template <typename, typename> struct is_subset_of : std::false_type { }; template <typename ... Types1, typename ... Types
#include <tuple>
#include <type_traits>
template <typename, typename>
struct is_subset_of : std::false_type
{
};
template <typename ... Types1, typename ... Types2>
struct is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>>
: std::true_type
{
// Should only be true_type if Types1 is a subset of Types2
};
int main() {
using t1 = std::tuple<int, double>;
using t2 = std::tuple<double, int>;
using t3 = std::tuple<int, double, char>;
static_assert(is_subset_of<t1, t1>::value, "err");
static_assert(is_subset_of<t1, t2>::value, "err");
static_assert(is_subset_of<t2, t1>::value, "err");
static_assert(is_subset_of<t2, t3>::value, "err");
static_assert(!is_subset_of<t3, t2>::value, "err");
}
#包括
#包括
模板
结构是:std::false类型的子集
{
};
模板
结构是
:std::true\u类型
{
//仅当Types1是Types2的子集时,才应为true\u type
};
int main(){
使用t1=std::tuple;
使用t2=std::tuple;
使用t3=std::tuple;
静态断言(是::value,“err”的子集);
静态断言(是::value,“err”的子集);
静态断言(是::value,“err”的子集);
静态断言(是::value,“err”的子集);
静态断言(!是::value,“err”的子集);
}
每种类型在一个集合中不允许出现一次以上
如果该解决方案能与C++11配合使用,那就太好了。如果您能使用C++17功能,我强烈建议您使用 不久前我不得不实现这个功能。我只是要复制粘贴我在那一点上提出的代码 我并不是说这是实施此类检查的最佳或最优雅的方式!我没有过多地考虑边缘案例;您可能需要调整代码以满足您的需求 澄清:
ContainsTypes
检查Rhs
是否是Lhs
的子集
模板
结构ContainsType;
模板
结构ContainsType
{
静态常量布尔值=ContainsType::VALUE;
};
模板
结构ContainsType
{
静态常量布尔值=真;
};
模板
结构ContainsType
{
静态常量布尔值=假;
};
// -----
模板
结构包含类型;
模板
结构ContainsTypes
{
静态常量bool VALUE=ContainsType::VALUE&&ContainsType::VALUE;
};
模板
结构ContainsTypes
{
静态常量布尔值=真;
};
您可以使用以下类来完成此操作:
template<typename... Set>
struct Check {
template<typename Type>
static constexpr bool verify() {
using accumulator_type = bool[];
bool check = false;
accumulator_type accumulator = { (check = check || std::is_same<Type, Set>())... };
(void)accumulator;
return check;
}
template<typename... SubSet>
static constexpr bool contain() {
using accumulator_type = bool[];
bool check = true;
accumulator_type accumulator = { (check = check && verify<SubSet>())... };
(void)accumulator;
return check;
}
};
模板
结构检查{
模板
静态constexpr bool verify(){
使用累加器_type=bool[];
布尔检查=假;
累加器类型累加器={(check=check | | std::is_same())…};
(b)蓄能器;
退货检查;
}
模板
静态constexpr bool contain(){
使用累加器_type=bool[];
布尔检查=真;
累加器类型累加器={(检查=检查和验证())…};
(b)蓄能器;
退货检查;
}
};
在一个基于函数的示例中使用它很简单。它遵循一个可能的实现,该实现适合您的代码:
#include <tuple>
#include <type_traits>
template<typename... Set>
struct Check {
template<typename Type>
static constexpr bool verify() {
using accumulator_type = bool[];
bool check = false;
accumulator_type accumulator = { (check = check || std::is_same<Type, Set>())... };
(void)accumulator;
return check;
}
template<typename... SubSet>
static constexpr bool contain() {
using accumulator_type = bool[];
bool check = true;
accumulator_type accumulator = { (check = check && verify<SubSet>())... };
(void)accumulator;
return check;
}
};
template <typename, typename>
struct is_subset_of;
template <typename ... Types1, typename ... Types2>
struct is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>> {
static constexpr bool value = Check<Types2...>::template contain<Types1...>();
};
int main() {
using t1 = std::tuple<int, double>;
using t2 = std::tuple<double, int>;
using t3 = std::tuple<int, double, char>;
static_assert(is_subset_of<t1, t1>::value, "err");
static_assert(is_subset_of<t1, t2>::value, "err");
static_assert(is_subset_of<t2, t1>::value, "err");
static_assert(is_subset_of<t2, t3>::value, "err");
static_assert(!is_subset_of<t3, t2>::value, "err");
}
#包括
#包括
模板
结构检查{
模板
静态constexpr bool verify(){
使用累加器_type=bool[];
布尔检查=假;
累加器类型累加器={(check=check | | std::is_same())…};
(b)蓄能器;
退货检查;
}
模板
静态constexpr bool contain(){
使用累加器_type=bool[];
布尔检查=真;
累加器类型累加器={(检查=检查和验证())…};
(b)蓄能器;
退货检查;
}
};
模板
结构是的子集;
模板
结构是{
static constexpr bool value=Check::template contain();
};
int main(){
使用t1=std::tuple;
使用t2=std::tuple;
使用t3=std::tuple;
静态断言(是::value,“err”的子集);
静态断言(是::value,“err”的子集);
静态断言(是::value,“err”的子集);
静态断言(是::value,“err”的子集);
静态断言(!是::value,“err”的子集);
}
作业在类检查中完成,其方法包含和验证
contain
成员函数是入口点。它使用一种常见的技巧(在等待折叠表达式时)来解压子集,并且需要对每个包含的类型进行显式检查。成员函数verify
通过将单个类型与给定集合相匹配来完成其余的工作
让我知道,如果我可以给你更多的细节,或者它是足够清楚的,因为它的立场
看到它正在运行。#包括
#包括
模板
constexpr bool contains=(std::is_same{}| |……);
模板
constexpr bool是=false的子集;
模板
constexpr bool是
=(包含&&…);
不完全是你要的,但是。。。为了好玩,使用std::is_base_of
可以创建(至少在C++14中)一个constepr
函数,该函数的工作方式与您的结构类似
下面是一个工作示例(仅限C++14)
#包括
#包括
#包括
模板
结构foo:std::tuple。。。
{ };
模板
bool isSubsetOf(std::tuple const&,std::tuple const&)
{
bool-ret{true};
使用un=int[];
使用d2=foo;
(void)un{(ret&=std::is_base_of::value,0)…};
返回ret;
}
int main()
{
使用t1=std::tuple;
使用t2=std::tuple;
使用t3=std::tuple;
std::cout我想我会参加比赛。这是一个C++11解决方案,就像OP要求的那样,我意识到C++17有很多更好的特性。它是一个类型唯一的解决方案(没有显式的静态常量bool
或类似的,只有真类型
和假类型
,它们有自己的内部bool
)
缺点是这个解决方案迫使我实现logical\u或和logical\u和
,我们将以连接和分离的形式得到它们
奇迹般的是,代码比代码短了一点,尽管可以说可读性较差
namespace detail
{
template<class T, class U>
struct logical_or : std::true_type{};
template<>
struct logical_or<std::false_type, std::false_type> : std::false_type{};
template<class...>
struct logical_and : std::false_type{};
template<>
struct logical_and<std::true_type, std::true_type> : std::true_type{};
}
template<class...>
struct contains : std::false_type{};
template<class T>
struct contains<T, T> : std::true_type{};
template<class Type, class Types2Head, class... Types2>
struct contains<Type, Types2Head, Types2...> : detail::logical_or<typename std::is_same<Type, Types2Head>::type, typename contains<Type, Types2...>::type>{};
template<class...>
struct is_subset_of : std::false_type{};
template<class Type1, class... Types2>
struct is_subset_of<std::tuple<Type1>, std::tuple<Types2...>> : contains<Type1, Types2...>{};
template<class Type1Head, class... Types1, class... Types2>
struct is_subset_of<std::tuple<Type1Head, Types1...>, std::tuple<Types2...>> : detail::logical_and<typename contains<Type1Head, Types2...>::type, typename is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>>::type>{};
名称空间详细信息
{
模板
结构逻辑_或:std::true_类型{};
模板
结构逻辑_或:std::false_类型{};
模板
结构逻辑_和:std::false_类型{};
模板
结构逻辑_和:std::true_类型{};
}
模板
结构包含:std
#include <tuple>
#include <type_traits>
template <typename T, typename... Ts>
constexpr bool contains = (std::is_same<T, Ts>{} || ...);
template <typename Subset, typename Set>
constexpr bool is_subset_of = false;
template <typename... Ts, typename... Us>
constexpr bool is_subset_of<std::tuple<Ts...>, std::tuple<Us...>>
= (contains<Ts, Us...> && ...);
#include <tuple>
#include <iostream>
#include <type_traits>
template <typename ... Ts>
struct foo : std::tuple<Ts>...
{ };
template <typename ... Ts1, typename ... Ts2>
bool isSubsetOf (std::tuple<Ts1...> const &, std::tuple<Ts2...> const &)
{
bool ret { true };
using un = int[];
using d2 = foo<Ts2...>;
(void)un { (ret &= std::is_base_of<std::tuple<Ts1>, d2>::value, 0)... };
return ret;
}
int main()
{
using t1 = std::tuple<int, double>;
using t2 = std::tuple<double, int>;
using t3 = std::tuple<int, double, char>;
std::cout << isSubsetOf(t1{}, t1{}) << std::endl; // print 1
std::cout << isSubsetOf(t1{}, t2{}) << std::endl; // print 1
std::cout << isSubsetOf(t2{}, t1{}) << std::endl; // print 1
std::cout << isSubsetOf(t1{}, t3{}) << std::endl; // print 1
std::cout << isSubsetOf(t3{}, t1{}) << std::endl; // print 0
}
namespace detail
{
template<class T, class U>
struct logical_or : std::true_type{};
template<>
struct logical_or<std::false_type, std::false_type> : std::false_type{};
template<class...>
struct logical_and : std::false_type{};
template<>
struct logical_and<std::true_type, std::true_type> : std::true_type{};
}
template<class...>
struct contains : std::false_type{};
template<class T>
struct contains<T, T> : std::true_type{};
template<class Type, class Types2Head, class... Types2>
struct contains<Type, Types2Head, Types2...> : detail::logical_or<typename std::is_same<Type, Types2Head>::type, typename contains<Type, Types2...>::type>{};
template<class...>
struct is_subset_of : std::false_type{};
template<class Type1, class... Types2>
struct is_subset_of<std::tuple<Type1>, std::tuple<Types2...>> : contains<Type1, Types2...>{};
template<class Type1Head, class... Types1, class... Types2>
struct is_subset_of<std::tuple<Type1Head, Types1...>, std::tuple<Types2...>> : detail::logical_and<typename contains<Type1Head, Types2...>::type, typename is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>>::type>{};
template <class T, class... U>
struct contains : std::disjunction<std::is_same<T, U>...>{};
template <typename...>
struct is_subset_of : std::false_type{};
template <typename... Types1, typename ... Types2>
struct is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>> : std::conjunction<contains<Types1, Types2...>...> {};
#include <tuple>
#include <type_traits>
template <typename T, typename ... Ts>
struct cType
{
static const bool value {
! std::is_same<std::integer_sequence<bool,
false, std::is_same<T, Ts>::value...>,
std::integer_sequence<bool,
std::is_same<T, Ts>::value..., false>>::value };
};
template <typename, typename>
struct isSubsetOf : std::false_type
{ };
template <template <typename...> class C1, template <typename...> class C2,
typename ... Ts1, typename ... Ts2>
struct isSubsetOf<C1<Ts1...>, C2<Ts2...>>
: std::integral_constant<bool,
std::is_same<std::integer_sequence<bool,
true, cType<Ts1, Ts2...>::value...>,
std::integer_sequence<bool,
cType<Ts1, Ts2...>::value..., true>
>::value>
{ };
int main()
{
using t1 = std::tuple<int, double>;
using t2 = std::tuple<double, int>;
using t3 = std::tuple<int, double, char>;
static_assert(isSubsetOf<t1, t1>::value, "err");
static_assert(isSubsetOf<t1, t2>::value, "err");
static_assert(isSubsetOf<t2, t1>::value, "err");
static_assert(isSubsetOf<t2, t3>::value, "err");
static_assert(!isSubsetOf<t3, t2>::value, "err");
}
template <typename T, T ... ts>
struct integerSequence
{ };
constexpr bool any_of() { return false; }
template<class...Bools>
constexpr bool any_of( bool b, Bools... bools ) {
return b || any_of(bools...);
}
constexpr bool all_of() { return true; }
template<class...Bools>
constexpr bool all_of( bool b, Bools...bools ) {
return b && all_of(bools...);
}
template<class T0, class...Ts>
struct contains_t : std::integral_constant<bool,
any_of( std::is_same<T0, Ts>::value... )
> {};
template<class Tuple0, class Tuple1>
struct tuple_subset_of;
template<class...T0s, class...T1s>
struct tuple_subset_of< std::tuple<T0s...>, std::tuple<T1s...> >:
std::integral_constant<bool,
all_of( contains_t<T0s, T1s...>::value... )
>
{};
#include <tuple>
#include <type_traits>
template <class T>
struct tag { };
template <class... Ts>
struct is_subset_of_helper: tag<Ts>... { };
template <class, class, class = void>
struct is_subset_of: std::false_type { };
template <bool...>
struct bool_pack { };
template <bool... Bs>
using my_and = std::is_same<bool_pack<Bs..., true>, bool_pack<true, Bs...>>;
template <class... Ts1, class... Ts2>
struct is_subset_of<std::tuple<Ts1...>, std::tuple<Ts2...>, typename std::enable_if< my_and< std::is_base_of<tag<Ts1>, is_subset_of_helper<Ts2...>>::value... >::value >::type >:
std::true_type { };
int main() {
using t1 = std::tuple<int, double>;
using t2 = std::tuple<double, int>;
using t3 = std::tuple<int, double, char>;
static_assert(is_subset_of<t1, t1>::value, "err");
static_assert(is_subset_of<t1, t2>::value, "err");
static_assert(is_subset_of<t2, t1>::value, "err");
static_assert(is_subset_of<t2, t3>::value, "err");
static_assert(!is_subset_of<t3, t2>::value, "err");
}