前言
自己在学习中的收获以及研究出来的写法。
一、检查一系列参数中所有类型都相同
这个利用C++17的fold expression特性很容易就能写出来。
假如有个可变模版参数的方法test:
template <typename T, typename... Ts>
void test() {
std::cout << std::conjunction_v<std::is_same<T, Ts>...>;
}
int main() {
test<int, int, int, int>();//true
test<int, int, float, int>();//false
}
std::conjunction是连接模版运算符,它的每个模版参数是std::std::bool_constant类型(类比做bool类型),
std::std::bool_constant下有两个using:
template<bool _Val>
using bool_constant = integral_constant<bool, _Val>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
std::conjunction的每个模版实参类似:
std::conjunction<std::true_type, std::true_type, std::false_type, ...>
相当于对所有bool做与(&&)运算,而最后运算出的值也是true_type或false_type。
如果单单如此,我们要让参数包的所有类型展开类似:
conjunction<is_same<T0, T1>, is_same<T1, T2>, is_same<T2, T3>, ...>
就得写一套递归程序解析参数包,但C++17的fold expression能帮助我们把参数包平铺开来。
二、检查让让参数包所有参数类型全不相等
这不是上个问题的直接取反,例如参数包[int, int, float, double, int],用上个问题的调用能得到false,取反得到true,但里面还有很多int重复了。
问题的复杂度来了,比较所有类型是否相同的复杂度是O(n),只要把1和2比,2和3比,有一个不同就可以得到false。
而是否全不相同,至少要让所有类型两两比较,遇到相同的返回false,复杂度是O(N^2)。
不过在此之前先完善下设施,标准库自带了std::is_same<Ty1, Ty2>,但没有类似is_not_some的功能,好在功能简单,只要仿照,很容易写出来:
template<class _Ty1, class _Ty2>
struct is_not_same : std::true_type {};
//偏特化,假如两个类型相同,匹配第二个
template<class _Ty1>
struct is_not_same<_Ty1, _Ty1> : std::false_type {};
//方便取值(true或false)的
template<class _Ty, class _Uty>
_INLINE_VAR constexpr bool is_not_same_v = is_not_same<_Ty, _Uty>::value;
接下来继续想,假如我们有一系列参数包[A, B, C, D, E],我希望能按照如下步骤进行解析:
1.先取出前两个参数,参数列表大致为:A, B, [C, D, E]
比较A和B,记做compare<A, B>
假如符合我们的想法,则将参数传递:
(compare<A, B>=true), A, C, [D, E]
否则向下传递:
(compare<A, B>=false), A, [C, D, E]
并结束递归
2.(compare<A, C>=true), A, D, [E]
3.(compare<A, D>=true), A, E, []
4.(compare<A, E>=true), A, [] 在此时结束递归
此时我们写出初始的包装类型:
template<
template <class _Ty1, class _Ty2> class _Compare,//比较器
class _First,//第一个参数
class _Second,//第二个参数
class... Rest //其他参数
>
//将比较器传递下去
//将比较结果传递下去
//将第一个参数传递下去
//将除了第二个参数外的其他参数传递下去
struct FirstCompareToOther
: _CompareStruct<_Compare, _Compare<_First, _Second>::value,
_First, Rest...>::type
{};
然后给上述的结构增加递归比较设施_CompareStruct。
//主模版
//当参数包Rest为空时结束递归
//或上一次比较数据Value为false时结束递归
template<
template <class A, class B> class _Compare,
bool Value,
class _First,
class... Rest
>
struct _CompareStruct {
using type = std::bool_constant<Value>;
};
//偏特化模版,当上一次比较为true时继续比较
template<
template <class A, class B> class _Compare,
class _First,
class _Next,
class... Rest
>
struct _CompareStruct<_Compare, true, _First, _Next, Rest...>
{
using type = typename _CompareStruct<_Compare, _Compare<_First, _Next>::value, _First, Rest...>::type;
};
现在通过比较器,可以将第一个参数与其他参数进行比较:
std::cout << FirstCompareToOther<std::is_same, int, int, int, int, int>::value;
//true
std::cout << FirstCompareToOther<std::is_same, float, int, int, int, int>::value;
//false
用我们自己写的is_not_same也是可以的:
//false
std::cout << FirstCompareToOther< is_not_same, int, int, double, int, double> ::value;
如我们所想存在三个int,不能称之为全不相同。但上述外码还不能做到比较全部的功能,假如我们有如下调用:
//true
std::cout << FirstCompareToOther < is_not_same, int, float, double, float, double> ::value;
int和后面的参数都不相同,但又两个float,两个double,因此还要继续编写代码,让每个参数都与后面所有的参数进行比较。
我们写下最后的代码:
template <class _First, class _Second, class... Rest>
struct all_is_not_same
: std::conjunction<FirstCompareToOther<is_not_same, _First, _Second, Rest...>, all_is_not_same<_Second, Rest...>>::type
{};
template <class _First, class _Second>
struct all_is_not_same<_First, _Second>
: is_not_same<_First, _Second>::type
{};
//false
std::cout << all_is_not_same<int, float, double, float, char>::value;
网友评论