zoukankan      html  css  js  c++  java
  • C++11 type_traits 之is_convertible源码分析

    请看源码:

      struct __sfinae_types
      {
        typedef char __one;
        typedef struct { char __arr[2]; } __two;
      };
    template<typename _From, typename _To,
               bool = __or_<is_void<_From>, is_function<_To>,
                            is_array<_To>>::value>
        struct __is_convertible_helper
        { static constexpr bool value = is_void<_To>::value; };
    
      template<typename _From, typename _To>
        class __is_convertible_helper<_From, _To, false>
        : public __sfinae_types
        {
          template<typename _To1>
            static void __test_aux(_To1);
    
          template<typename _From1, typename _To1>
            static decltype(__test_aux<_To1>(std::declval<_From1>()), __one())
        __test(int);
    
          template<typename, typename>
            static __two __test(...);
    
        public:
          static constexpr bool value = sizeof(__test<_From, _To>(0)) == 1;
        };
    
      /// is_convertible
      template<typename _From, typename _To>
        struct is_convertible
        : public integral_constant<bool,
                       __is_convertible_helper<_From, _To>::value>
        { };

    1.__is_convertible_helper是拥有三个模版参数的类模版,其中最后一个非类型模版参数有默认值。__or_<is_void<_From>, is_function<_To>, is_array<_To>>::value,只要其中任意一个为真,那么结果即为真。

    2.__is_convertible_helper<_From, _To, false>__is_convertible_helper的偏特化,将bool的值设置为false,也就是说__or_<is_void<_From>, is_function<_To>, is_array<_To>>::value=false时,会转入此模版类。

    3.对于为true的情况,is_void<_To>::value直接指示出类型是否可以转换。我们仔细分析一下:

       a.is_void<_From>::value为true,则能否转换结果为is_void<_To>::value,from为void,to也为void即可转换。

       b.如果is_array<_To>::value,is_function<_To>::value某个为true,则能否转换结果为is_void<_To>::value,在这里必然不能转换。

    4.对于为false的情况,关键在于变长函数参数和sizeof表达式的妙用,如果没有这本书《C++设计新思维,泛型编程与设计模式之运用》我根本看不懂这些源码。

       a. template<typename _From1, typename _To1> static decltype(__test_aux<_To1>(std::declval<_From1>()), __one()) __test(int);

            __test()是一个函数,函数参数类型int,返回值由decltype推导而来,decltype里面是一个逗号表达式,如果__test_aux<_To1>(std::declval<_From1>())是有效的,那么decltype返回__one()的类型。

       b.如果表达式是无效的,则__two __test(...)被选择。在编译时,我们可以知道这两个函数一个返回类型__one,一个返回类型__two,一个是单独char,一个是char数组长度为2

       c.static constexpr bool value = sizeof(__test<_From, _To>(0)) == 1,调用函数,让编译器选择使用__test(int)还是__test(...),能进行类型转换就选择第一个,然后sizeof就返回值类型长度,指示出是否能进行转换。

    一段示例代码,说明一些基本原理。

    void convert(double)
    {
     cout<<"double..."<<endl;
    }
    
    class H
    {
       public:
       template <typename X> static decltype(convert(X()),string()) hello(int){cout<<"hello..."<<endl;return "c";}
       template <typename >  static char hello(...){cout<<"..."<<endl;return 'c';}
    
    
    };
    
    int main()
    {
    
    
         cout<<"charSize:"<<sizeof(char)<<endl;
         cout<<"stringSize:"<<sizeof(string)<<endl;
         cout<<"--------------------"<<endl;
         cout<<sizeof(H::hello<string>(0))<<endl;
         cout<<sizeof(H::hello<long>(0))<<endl;
         cout<<"--------------------"<<endl;
         H::hello<string>(0);
         H::hello<long>(0);
         H::hello<int>(0);
         H::hello<float>(0);
    
    }

    能转换的类型,sizeof输出8,不能呢过转换输出1,编译器根据语法规则选择哪个函数可以执行。

  • 相关阅读:
    带你了解什么是Push消息推送
    小白学习如何打日志
    最近学到的前后端分离知识
    记一次愚蠢的操作--线程安全问题
    在工作中常用到的SQL
    在工作中常用的Linux命令
    记一次愚蠢的经历--String不可变性
    在公司做的项目和自己在学校做的有什么区别?
    程序员的快乐就是这么朴素无华且枯燥
    《大型网站系统与Java中间件》读书笔记 (中)
  • 原文地址:https://www.cnblogs.com/tangzhenqiang/p/4136728.html
Copyright © 2011-2022 走看看