C++学习---类型萃取---std::conditional与逻辑与或非

229 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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与逻辑与或非实现了类型萃取模块的逻辑运算,能够处理多个输入的类型,并得到它们最终的运算结果和类型,这在一些需要判断输入类型是否全部一致的场景十分有用。