美文网首页
第二章 技术

第二章 技术

作者: szn好色仙人 | 来源:发表于2018-04-11 22:19 被阅读0次

    编译期Assertions

    //动态检测
    #include <cassert>
    
    template<typename TypeOut, typename TypeIn>
    TypeOut safe_reinterpret_cast(TypeIn tIn)
    {
        assert(sizeof(TypeIn) <= sizeof(TypeOut));
        return reinterpret_cast<TypeOut>(tIn);
    }
    
    int main()
    {
        void* pValue = nullptr;
        char nValue0 = reinterpret_cast<char>(pValue);          //正常运行
        char nValue1 = safe_reinterpret_cast<char>(pValue);     //引发中断
        return 0;
    }
    
    //静态检测,但是编译器报的错并不直接
    
    //结合常量表达式和编译器自动检查分配0数组错误
    #define STATIC_CHECK(expr) { char aTem[expr ? 1 : 0]; }
    
    template<typename TypeOut, typename TypeIn>
    TypeOut safe_reinterpret_cast(TypeIn tIn)
    {
        STATIC_CHECK(sizeof(TypeIn) <= sizeof(TypeOut));
        return reinterpret_cast<TypeOut>(tIn);
    }
    
    int main()
    {
        void* pValue = nullptr;
        char nValue0 = reinterpret_cast<char>(pValue);               //编译通过
    
        //char nValue1 = safe_reinterpret_cast<char>(pValue);        //编译失败
        //error C2466: 不能分配常量大小为 0 的数组
    
        long long nValue2 = safe_reinterpret_cast<long long>(pValue);//编译成功
        return 0;
    }
    
    //最终版:检测任意常量表达式,且能自定义编译器报错的字符串
    
    template<bool> class CCompileTimeCheck
    {
    public:
        CCompileTimeCheck(...);
    };
    template<> class CCompileTimeCheck<false> {};
    
    
    #define STATIC_CHECK(expr, msg)                     \
    {                                                   \
        class C##msg {};                                \
        sizeof((CCompileTimeCheck<expr> (C##msg())));   \
    }
    
    
    template<typename TypeOut, typename TypeIn>
    TypeOut safe_reinterpret_cast(TypeIn tIn)
    {
        STATIC_CHECK(sizeof(TypeOut) >= sizeof(TypeIn), Szn);
    
        return reinterpret_cast<TypeOut>(tIn);
    }
    
    
    int main()
    {
        void* pValue = nullptr;
        long long nValue0 = safe_reinterpret_cast<long long>(pValue);//正常编译
    
        char nValue1 = safe_reinterpret_cast<char>(pValue);          //编译出错
    /*  
        error C2440: “<function-style-cast>”: 
        无法从“safe_reinterpret_cast::CSzn”转换为“CCompileTimeCheck<false>”
    */
        return 0;
    }
    

    对象构造、函数声明、名称查找的规则组合体现的一个例子

    #include <cstdio>
    #include <typeinfo>
    
    
    class CTest
    {
    public:
        CTest()             { printf("CTest\n"); }
        CTest(CTest&)       { printf("CTest Copy\n"); }
    };
    
    class CTest1
    {
    public:
        CTest1()            { printf("CTest1\n"); }
        CTest1(CTest&)      { printf("CTest1 Create\n"); }
        CTest1(CTest1&)     { printf("CTest1 Copy\n"); }
    };
    
    
    int main()
    {
        {
            int nV0 = double(2.2);          //强制类型转换 nV0 = 2
            //反汇编: 008F3E2C  mov         dword ptr [nV0],2 
    
            int nV1 = (double)2.2;          //强制类型转换 nV1 = 2
            //反汇编: 008F3E33  mov         dword ptr [nV1],2  
    
            auto nV2 = int(double());       //强制类型转换 nV2 = 0
            //反汇编: 008F3E3A  mov         dword ptr [nV2],0  
    
            auto nV3 = static_cast<int>(double());
            //反汇编: 01003E25  mov         dword ptr [nV3],0  
    
            auto pStr = typeid(int(double())).name();
            //pStr = "int __cdecl(double (__cdecl*)(void))"
    
            pStr = typeid((int(double()))).name();
            //pStr = "int"
    
            pStr = typeid(double()).name();
            //pStr = "double __cdecl(void)"
    
            pStr = typeid((double())).name();
            //pStr = "double"
    
    
            //int (double);                 //编译失败
            int Fun(double);                //函数声明
            pStr = typeid(Fun).name();      //pStr = "int __cdecl(double)"
    
            //sizeof 需要一个表达式或类型
            //sizeof(Fun);  //error Cun2070: “int (double)”: 非法的 sizeof 操作数
            int nV4 = sizeof(Fun(1.1));     //Fun即使不进行定义,也不会报错 nV4 = 4
            //反汇编: 009C3ECD  mov         dword ptr [nV4],4  
        }
    
        {
            auto Test1 = CTest1(CTest());       //输出"CTest" "CTest1 Create"
            (CTest1(CTest()));                  //输出"CTest" "CTest1 Create"
    
            CTest1 CTest();                     //函数声明 
            CTest1 (CTest());                   //函数声明 等价上一句
            //从此 名字 CTest就不是自定义的类了,而是一个函数名称
    
            auto it = CTest1(CTest());  //输出"Suprise" "CTest1" "CTest1 Copy"
            auto it1 = CTest();         //输出"Suprise" "CTest1"
    
            printf("");
        }
    
        return 0;
    }
    
    
    CTest1(CTest())     //等价于 CTest1 CTest() 此段代码是是CTest函数的定义
    {
        printf("Suprise\n");
    
        return CTest1();
    }
    

    模板偏特化

    • 模板类可以全特化也可以偏特化
    • 模板类的成员函数只能全特化,不能偏特化(参见第一章)
    • namespace-level的函数不能偏特化,但是可以被轻易的重载

    常数映射为类型

    • 应用场景:
      有必要根据某个编译期常数调用一个或数个不同的函数
      编译期实施分派(if-else switch语句)
    template<int nValue>
    struct IntToType
    {
        enum { eValue = nValue };
    };
    
    
    template<typename T, bool bTest>
    class CTest
    {
    public:
        void Fun()
        {
            //编译期分派
            if (bTest)
            {
                tValue.SomeFun();
            }
        }
    
    private:
        T tValue;
    };
    
    template<typename T, bool bTest>
    class CTest1
    {
    private:
        void Fun(IntToType<true>)
        {
            tValue.SomeFun();
        }
    
        void Fun(IntToType<false>){}
    
    public:
        //编译期分派
        void Suprise()
        {
            Fun(IntToType<bTest>());
        }
    
    private:
        T tValue;
    };
    
    
    int main()
    {
        int nValue = 10;
        auto it0 = IntToType<10>();         //编译成功
        //auto it1 = IntToType<nValue>();   //编译出错
        //“IntToType”: 模板参数“nValue”:“nValue”: 局部变量不能用作非类型参数
    
        CTest<int, false> Test;
        //Test.Fun();               //编译出错
    
        CTest1<int, false> Test1;
        Test1.Suprise();            //编译成功
        return 0;
    }
    

    类型对类型的映射

    //类型映射到类型
    template<typename T>
    struct STypeToType{ typedef T TypeOriginal; };
    
    template<typename T, typename U>
    T* Create(const U& u, STypeToType<T>)
    {
        return new T(u);
    }
    
    template<typename U>
    CTest* Create(const U& u, STypeToType<CTest>)
    {
        //根据类型定制的版本
        return new CTest(u, -1);
    }
    

    型别选择

    • 一个应用场景:比如根据不同的类型,在vector中选择放置对象本身还是对象的指针
    #include <vector>
    #include <typeinfo>
    
    
    using std::vector;
    
    
    //方法一:扩展性差
    template<typename T, bool bRe>
    struct STest
    {
        typedef T* Type;
    };
    
    template<typename T>
    struct STest<T, false>
    {
        typedef T Type;
    };
    
    
    //方法二:扩展性好
    template<bool bRe, typename T, typename U>
    struct SSelect
    {
        typedef T Type;
    };
    
    template<typename T, typename U>
    struct SSelect<false, T, U>
    {
        typedef U Type;
    };
    
    
    int main()
    {
        //it0 = "int *"
        auto it0 = typeid(STest<int, true>::Type).name();
    
        //it1 =  "int"
        auto it1 = typeid(STest<int, false>::Type).name();
    
        //it2 = "int"
        auto it2 = typeid(SSelect<true, int, double>::Type).name();
    
        //it3 = "double"
        auto it3 = typeid(SSelect<false, int, double>::Type).name();    
        
        return 0;
    }
    

    编译期间侦查可转换性和继承性

    • 面对两个陌生的类型T和U,如何得知U是否继承于T?在编译期间发掘这样的关系,意味着不必使用dynamic_cast,后者会所耗执行效率。
    template<typename T, typename U>
    class CConversion
    {
        //此类可以用于编译期间侦测类型的可转换性
    
        typedef char Small;
        class CBig { char aBuff[2]; };
        //定义class CBig { char aBuff[2]; }; 确保sizeof(CBig) != sizeof(Small)
    
        static Small Fun(U);
        static CBig Fun(...);
    /*
        若T能转换为U则调用Fun(U), 否则调用Fun(...)
        则有如下结论:
        若T能转换为U : Fun返回Small
        若T不能转换为U : Fun返回CBig
    */
    
        static T MakeT();
        //定义一个不完全函数,即使T类型的构造函数是private类型的也无妨
    
    public:
        enum 
        {
            eExists = sizeof(Fun(MakeT())) == sizeof(Small)
            //若T能转换为U则      Exists = true
            //若T不能转换为U则 Exists = false
    
    /*
            sizeof可以用在任何表达式上,不论后者有多复杂,sizeof会直接传回大小,
            不需要等到执行期才评估。这意味着sizeof可以感知重载、模板具现、转换规则
            ,或任何可以发生在C++表达式上的机制
    */
        };
    
        enum
        {
            eExistsToWay = eExists && CConversion<U, T>::eExists
        };
    
        enum
        {
            eSameType = false
        };
    };
    
    
    //模板偏特化
    template<typename T>
    class CConversion<T, T>
    {
    public:
        enum { eExists = true, eExistsToWay = true, eSameType = true };
    };
    
    
    class CFather {};
    class CChild : public CFather {};
    
    
    int main()
    {
        bool aRe0[] = 
        {
            CConversion<double, int>::eExists,      //true
            CConversion<int, char*>::eExists,       //false
            CConversion<CChild*, CFather*>::eExists,//true
            CConversion<CFather*, CChild*>::eExists,//false
        };
    
        bool aRe1[] = 
        {
            //true
            CConversion<double, int>::eExistsToWay,
    
            //false
            CConversion<CChild*, CFather*>::eExistsToWay,
    
        };
    
        bool aRe2[] =
        {
            CConversion<int, int>::eSameType,       //true
            CConversion<int, double>::eSameType,    //false
        };
    
        return 0;
    }
    

    Type Traits

    //类型判断
    
    #include <vector>
    using std::vector;
    
    
    template<typename T>
    class CTypeTraits
    {
    public:
        enum
        {
            eNormal,
            eNference,
            eNormalPoint,
            ePointToMember,
        };
    
    private:
        template<typename U> struct STypeTest
        {
            enum { eResult = eNormal };
        };
    
        template<typename U> struct STypeTest<U&>
        {
            enum { eResult = eNference };
        };
    
        template<typename U> struct STypeTest<U* const>
        {
            enum { eResult = eNormalPoint };
        };
    
        template<typename U> struct STypeTest<U*>
        {
            enum { eResult = eNormalPoint };
        };
    
        template<typename U, typename V>
        struct STypeTest<U V::*>
        {
            enum { eResult = ePointToMember };
        };
    
        template<typename U, typename V>
        struct STypeTest<U (V::*)() const>
        {
            //类的常量 成员/成员函数 指针
            enum { eResult = ePointToMember };
        };
    
    public:
        enum { eType = STypeTest<T>::eResult };
    };
    
    
    struct A
    {
        int value;
        int Fun();
    };
    
    
    int main()
    {
        //语法 : 定义一个指向类的常量成员函数的指针
        vector<int>::size_type (vector<int>::*p)() const = &vector<int>::size;
    
        char aRe[] = 
        {
            CTypeTraits<vector<char>::iterator>::eType, //0
            CTypeTraits<char>::eType,                   //0
            CTypeTraits<char&>::eType,                  //1
            CTypeTraits<char* const>::eType,            //2
            CTypeTraits<char*>::eType,                  //2
            CTypeTraits<decltype(&A::value)>::eType,    //3
            CTypeTraits<decltype(&A::Fun)>::eType,      //3
            CTypeTraits<decltype(&vector<int>::size)>::eType,       //3
        };
    
        return 0;
    }
    
    //利用偏特化 去掉 const 属性
    template<typename T>
    class CDelConst
    {
    private:
        template<typename U> struct SNotConst
        {
            typedef U Type;
        };
    
        template<typename U> struct SNotConst<const U>
        {
            typedef U Type;
        };
    
    public:
        typedef typename SNotConst<T>::Type Type;
    };
    

    相关文章

      网友评论

          本文标题:第二章 技术

          本文链接:https://www.haomeiwen.com/subject/shnzhftx.html