C++学习---类型萃取---is_integral && is_floating_point

466 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

背景

定义在<type_traits>中,用于判断一个类型是否是int类型,是否浮点类型,属于基础的类型判断。

代码实现

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源码,这里仅用作相关原理分析。

实现分析

is_integral

  template<typename>
    struct __is_integral_helper
    : public false_type { };

  template<>
    struct __is_integral_helper<bool>
    : public true_type { };

  template<>
    struct __is_integral_helper<char>
    : public true_type { };

...signed char...
...unsigned char...
...wchar_t...
...char16_t...
...char32_t...
...short...
...unsigend short...
...int...
...unsigend int...
...long...
...unsigned long...
...long long...
...unsigned long long...

  /// is_integral
  template<typename _Tp>
    struct is_integral
    : public __is_integral_helper<typename remove_cv<_Tp>::type>::type
    { };

可以看到,实际上还是借助了模板特化的方法,对一系列int类型(bool,char...unsigned long long ),直接特化为继承true_type的类(value值为true),原始的类模板直接继承false_type类(value值为false)。最后在传入各个特化模板之前,需要先调用remove_cv去除const和volatile属性。

is_floating_point

  template<typename>
    struct __is_floating_point_helper
    : public false_type { };

  template<>
    struct __is_floating_point_helper<float>
    : public true_type { };

  template<>
    struct __is_floating_point_helper<double>
    : public true_type { };

  template<>
    struct __is_floating_point_helper<long double>
    : public true_type { };

#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128)
  template<>
    struct __is_floating_point_helper<__float128>
    : public true_type { };
#endif

  /// is_floating_point
  template<typename _Tp>
    struct is_floating_point
    : public __is_floating_point_helper<typename remove_cv<_Tp>::type>::type
    { };

is_floating_point的方式也是一致的,针对float/double/long double/__float128做了特化版本,同样的,使用remove_cv去除const和volatile属性。

使用案例

#include <iostream>             
#include <type_traits>                                  
                                                                     
class EmptyClass{};                                                    
                                                                                                   
enum EnumTest : int{};                                                             
                                                                               
struct IntStruct{int x;};                                                                            
using IntStructMemberType = decltype(IntStruct::x);
                                                              
                                                                                                                         
int main(){                                                                    
    std::cout << std::boolalpha;                                                 
    std::cout << "------is_integral------" << std::endl;                                 
    std::cout << "int:" << std::is_integral<int>::value << std::endl;
    std::cout << "char:" << std::is_integral<char>::value << std::endl;
    std::cout << "const volatile int:" << std::is_integral<const volatile int>::value << std::endl;                      
    std::cout << "EmptyClass:" << std::is_integral<EmptyClass>::value << std::endl;
    std::cout << "EnumTest:" << std::is_integral<EnumTest>::value << std::endl;
    std::cout << "IntStructMemberType:" << std::is_integral<IntStructMemberType>::value << std::endl;
                                      
    std::cout << "------is_floating_point------" << std::endl;
    std::cout << "int:" << std::is_floating_point<int>::value << std::endl;                                                                              
    std::cout << "float:" << std::is_floating_point<float>::value << std::endl;
    std::cout << "float&:" << std::is_floating_point<float&>::value << std::endl;
    std::cout << "EmptyClass:" << std::is_floating_point<EmptyClass>::value << std::endl;                                
                      
    return 0;
}

需要注意的点:

  • 空类并不是int型;
  • 继承int型的枚举不是int型;
  • 类中对应成员变量的类型与元类型保持一致;
  • 空类不是float型;
  • float&不是float型,因为有引用的存在

总结

is_integral 和 is_floating_point利用了模板特化的方式,指定了一些固定的类型可以返回true,其他类型返回false.

is_integral :bool/char/signed char/unsigned char/wchar_t/char16_t/char32_t/short/unsigend short/int/unsigend int/long/unsigned long/long long/unsigned long long

is_floating_point :loat/double/long double/__float128