开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情
背景
定义在<type_traits>中,用于判断一个类型是否是类的成员对象指针,是否是类的成员函数,属于基础的类型判断。
代码实现
gcc官网:gcc.gnu.org/
gcc代码下载:mirrors.tuna.tsinghua.edu.cn/help/gcc.gi…
gcc版本代码:gcc-7.5.0(branch分支)
文件位置:gcc/libstdc++-v3/include/std/type_traits
注意:以下的代码实现省略了一些宏定义部分,实际的代码还是参考gcc源码,这里仅用作相关原理分析。
实现分析
conditional
接受三个类型输入,根据第一个bool值决定将哪一个作为当前的type类型,如果为true,则type为_Iftrue,否则为_Iffalse,也是使用模板特化实现的。
// Primary template.
/// Define a member typedef @c type to one of two argument types.
template<bool _Cond, typename _Iftrue, typename _Iffalse>
struct conditional
{ typedef _Iftrue type; };
// Partial specialization for false.
template<typename _Iftrue, typename _Iffalse>
struct conditional<false, _Iftrue, _Iffalse>
{ typedef _Iffalse type; };
_and
接受多个类型参数,如果这几个类型的value都为true,返回true,否则返回false;
如果没有类型参数,直接返回true;只有一个类型参数,返回该类型的value。
template<typename...>
struct __and_;
template<>
struct __and_<>
: public true_type
{ };
template<typename _B1>
struct __and_<_B1>
: public _B1
{ };
template<typename _B1, typename _B2>
struct __and_<_B1, _B2>
: public conditional<_B1::value, _B2, _B1>::type
{ };
template<typename _B1, typename _B2, typename _B3, typename... _Bn>
struct __and_<_B1, _B2, _B3, _Bn...>
: public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, _B1>::type
{ };
从上面的模板代码也可以看到具体的实现细节:
- 无参数时直接继承true_type;
- 有一个参数时,继承该类型;
- 有两个参数时,使用上面的conditional,如果_B1::value为true,继承_B2,否则继承_B1,这样就达到了与运算的效果;
- 有多个参数时,则类似两个参数的情况,迭代调用__and_即可。
_or
接受多个类型参数,如果这几个类型的value有一个为true,返回true,否则返回false;
如果没有类型参数,直接返回false;只有一个类型参数,返回该类型的value。
template<typename...>
struct __or_;
template<>
struct __or_<>
: public false_type
{ };
template<typename _B1>
struct __or_<_B1>
: public _B1
{ };
template<typename _B1, typename _B2>
struct __or_<_B1, _B2>
: public conditional<_B1::value, _B1, _B2>::type
{ };
template<typename _B1, typename _B2, typename _B3, typename... _Bn>
struct __or_<_B1, _B2, _B3, _Bn...>
: public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type
{ };
从上面的模板代码也可以看到具体的实现细节:
- 无参数时直接继承false_type;
- 有一个参数时,继承该类型;
- 有两个参数时,使用上面的conditional,如果_B1::value为true,继承_B1,否则继承_B2,这样就达到了或运算的效果;
- 有多个参数时,则类似两个参数的情况,迭代调用__or_即可。
_not
这个理解起来就更简单了,直接取出_Pp::value,然后取反即可。
template<typename _Pp>
struct __not_
: public __bool_constant<!bool(_Pp::value)>
{ };
conjunction
对__and_进行封装
template<typename... _Bn>
struct conjunction
: __and_<_Bn...>
{ };
disjunction
对__or_进行封装
template<typename... _Bn>
struct disjunction
: __or_<_Bn...>
{ };
negation
对__not_进行封装
template<typename _Pp>
struct negation
: __not_<_Pp>
{ };
使用案例
#include <iostream>
#include <type_traits>
int main(){
std::cout << std::boolalpha;
std::cout << "std::conjunction<std::is_integral<int>,std::is_pointer<int*>>::value:\t"
<< std::conjunction<std::is_integral<int>,std::is_pointer<int*>>::value << std::endl;
std::cout << "std::disjunction<std::is_integral<float>,std::is_pointer<int*>>::value:\t"
<< std::conjunction<std::is_integral<float>,std::is_pointer<int*>>::value << std::endl;
std::cout << "std::negation<std::is_integral<float>>::value:\t\t"
<< std::negation<std::is_integral<float>>::value << std::endl;
return 0;
}
案例也比较简单,检查各个类型是否与预期一致,然后返回对应值。
总结
std::conditional与逻辑与或非实现了类型萃取模块的逻辑运算,能够处理多个输入的类型,并得到它们最终的运算结果和类型,这在一些需要判断输入类型是否全部一致的场景十分有用。