美文网首页
C++11 自定义类型萃取器

C++11 自定义类型萃取器

作者: FredricZhu | 来源:发表于2022-01-19 15:43 被阅读0次

    本文是C++ Templates一书,类型分类一章的源码。
    自己亲手敲感觉敲了1个半小时才敲完的样子。
    大家平时做项目不需要自己定义。直接include type_traits头文件就可以。什么都有了。
    这里这个示例主要是展示一些使用SFINE做类型萃取的技巧。
    CMakeLists.txt

    cmake_minimum_required(VERSION 2.6)
    
    if(APPLE)
        message(STATUS "This is Apple, do nothing.")
    elseif(UNIX)
        message(STATUS "This is linux, set CMAKE_PREFIX_PATH.")
        set(CMAKE_PREFIX_PATH /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/share)
    endif(APPLE)
    
    project(type2)
    
    add_definitions(-std=c++17)
    
    add_definitions(-g)
    
    find_package(ZLIB)
    
    find_package(glog REQUIRED)
    
    find_package(OpenCV REQUIRED )
    
    find_package(Boost REQUIRED COMPONENTS
        system
        filesystem
        serialization
        program_options
        thread
        )
    
    find_package(DataFrame REQUIRED)
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set INCLUDE_DIRS")
    set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include /usr/local/iODBC/include /opt/snowflake/snowflakeodbc/include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ {CMAKE_CURRENT_SOURCE_DIR}/../)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set INCLUDE_DIRS")
        set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ ${CMAKE_CURRENT_SOURCE_DIR}/../)
    endif(APPLE)
    
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set LINK_DIRS")
        set(LINK_DIRS /usr/local/lib /usr/local/iODBC/lib /opt/snowflake/snowflakeodbc/lib/universal)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set LINK_DIRS")
        set(LINK_DIRS ${Boost_INCLUDE_DIRS} /usr/local/lib /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/lib)
    endif(APPLE)
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set ODBC_LIBS")
        set(ODBC_LIBS iodbc iodbcinst)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set LINK_DIRS")
        set(ODBC_LIBS odbc odbcinst ltdl)
    endif(APPLE)
    
    include_directories(${INCLUDE_DIRS})
    LINK_DIRECTORIES(${LINK_DIRS})
    
    file( GLOB main_file_list ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 
    
    file( GLOB APP_SOURCES  ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/http/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/yaml/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/df/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/death_handler/impl/*.cpp)
    
    add_library(${PROJECT_NAME}_lib SHARED ${APP_SOURCES})
    target_link_libraries(${PROJECT_NAME}_lib ${Boost_LIBRARIES} ZLIB::ZLIB glog::glog DataFrame::DataFrame ${OpenCV_LIBS})
    target_link_libraries(${PROJECT_NAME}_lib  ssl crypto libgtest.a pystring libyaml-cpp.a libgmock.a ${ODBC_LIBS} libnanodbc.a pthread dl backtrace)
    
    foreach( main_file ${main_file_list} )
        file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${main_file})
        string(REPLACE ".cpp" "" file ${filename})
        add_executable(${file}  ${main_file})
        target_link_libraries(${file} ${PROJECT_NAME}_lib)
    endforeach( main_file ${main_file_list})
    

    typet.hpp

    #ifndef _FREDRIC_TYPE_T_HPP_
    #define _FREDRIC_TYPE_T_HPP_
    
    // 是否基础类型,主模板
    template <typename T>
    class IsFundaT {
        public:
            enum {Yes=0, No=1};
    };
    
    // 基础类型的模板偏特化
    #define MK_FUNDA_TYPE(T) \
     template <> \
     class IsFundaT<T> { \
         public: \
            enum {Yes=1, No=0}; \
     }; \
    
    MK_FUNDA_TYPE(void)
    MK_FUNDA_TYPE(bool)
    MK_FUNDA_TYPE(char)
    MK_FUNDA_TYPE(signed char)
    MK_FUNDA_TYPE(unsigned char)
    MK_FUNDA_TYPE(wchar_t)
    
    MK_FUNDA_TYPE(signed short)
    MK_FUNDA_TYPE(unsigned short)
    MK_FUNDA_TYPE(signed int)
    MK_FUNDA_TYPE(unsigned int)
    MK_FUNDA_TYPE(signed long)
    MK_FUNDA_TYPE(unsigned long)
    
    #if LONGLONG_EXITS
        MK_FUNDA_TYPE(signed long long)
        MK_FUNDA_TYPE(unsigned long long)
    #endif
    
    MK_FUNDA_TYPE(float)
    MK_FUNDA_TYPE(double)
    MK_FUNDA_TYPE(long double)
    
    #undef MK_FUNDA_TYPE
    
    // CompondT 主模板
    template <typename T>
    class CompondT {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=0,
                IsArrayT=0,
                IsFuncT=0,
                IsPtrMemT=0
            };
    
            using BaseT = T;
            using BottomT = T;
            using ClassT = CompondT<void>;
    };
    
    // 成员函数指针定义
    template <typename T>
    class IsFunctionT {
        private:
            using One = char;
            using Two = struct {char a[2];};
            // 泛化不能匹配的任意类型
            template <typename U> static One test(...);
            // 除了函数,其他类型都能转换成 U类型的数组指针
            template <typename U> static Two test(U (*) [1]);
        
        public:
            enum {Yes = sizeof(IsFunctionT<T>::test<T>(0)) == 1};
            enum {No = !Yes};
    };
    
    template <typename T>
    class IsFunctionT<T&> {
        public:
            enum {Yes=0};
            enum {No=!Yes};
    };
    
    template <>
    class IsFunctionT<void> {
        public:
            enum {Yes=0};
            enum {No=!Yes};
    };
    
    template <>
    class IsFunctionT<void const> {
        public:
            enum {Yes=0};
            enum {No=!Yes};
    };
    
    template <>
    class IsFunctionT<void volatile> {
        public:
            enum {Yes=0};
            enum {No=!Yes};
    };
    
    template <>
    class IsFunctionT<void const volatile> {
        public:
            enum {Yes=0};
            enum {No=!Yes};
    };
    
    
    // 针对引用类型的偏特化
    template <typename T>
    class CompondT<T&> {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=1,
                IsArrayT=0,
                IsFuncT=0,
                IsPtrMemT=0
            };
    
            using BaseT = T;
            using BottomT = typename CompondT<T>::BottomT;
            using ClassT = CompondT<void>;
    };
    
    // 针对指针类型的偏特化
    template <typename T>
    class CompondT<T*> {
        public: 
            enum {
                IsPtrT=1, 
                IsRefT=0,
                IsArrayT=0,
                IsFuncT=0,
                IsPtrMemT=0
            };
    
            using BaseT = T;
            using BottomT = typename CompondT<T>::BottomT;
            using ClassT = CompondT<void>;
    };
    
    #include <cstddef>
    // 针对数组类型的偏特化
    template <typename T, std::size_t N>
    class CompondT<T[N]> {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=0,
                IsArrayT=1,
                IsFuncT=0,
                IsPtrMemT=0
            };
    
            using BaseT = T;
            using BottomT = typename CompondT<T>::BottomT;
            using ClassT = CompondT<void>;
    };
    
    
    // 针对空数组的偏特化
    template <typename T>
    class CompondT<T[]> {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=0,
                IsArrayT=1,
                IsFuncT=0,
                IsPtrMemT=0
            };
    
            using BaseT = T;
            using BottomT = typename CompondT<T>::BottomT;
            using ClassT = CompondT<void>;
    };
    
    
    // 针对成员指针的偏特化
    template <typename T, typename C>
    class CompondT<T C::*> {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=0,
                IsArrayT=0,
                IsFuncT=0,
                IsPtrMemT=1
            };
    
            using BaseT = T;
            using BottomT = typename CompondT<T>::BottomT;
            using ClassT = C;
    };
    
    // 针对0参 普通函数的特化
    template <typename R>
    class CompondT<R()> {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=0,
                IsArrayT=0,
                IsFuncT=1,
                IsPtrMemT=0
            };
    
            using BaseT = R();
            using BottomT = R();
            using ClassT = CompondT<void>;
    };
    
    // 针对1参 普通函数的特化
    template <typename R, typename P1>
    class CompondT<R(P1)> {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=0,
                IsArrayT=0,
                IsFuncT=1,
                IsPtrMemT=0
            };
    
            using BaseT = R(P1);
            using BottomT = R(P1);
            using ClassT = CompondT<void>;
    };
    
    // 针对多参 普通函数的特化
    template <typename R, typename P1>
    class CompondT<R(P1, ...)> {
        public: 
            enum {
                IsPtrT=0, 
                IsRefT=0,
                IsArrayT=0,
                IsFuncT=1,
                IsPtrMemT=0
            };
    
            using BaseT = R(P1);
            using BottomT = R(P1);
            using ClassT = CompondT<void>;
    };
    
    
    // 枚举类型处理
    struct SizeOverOne { char c[2]; };
    
    // 枚举不能转换成 Function和Array
    template <typename T, bool convert_possible = !CompondT<T>::IsFuncT && !CompondT<T>::IsArrayT>
    class ConsumeUDC {
        public:
            operator T() const;
    };
    
    // 不能转换的类型的偏特化,啥都不做
    template <typename T>
    class ConsumeUDC<T, false> {
    };
    
    // 枚举类型也不能转换为void类型
    template <bool convert_possible>
    class ConsumeUDC<void, convert_possible> {
    };
    
    
    char enum_check(bool);
    char enum_check(char);
    char enum_check(signed char);
    char enum_check(unsigned char);
    char enum_check(wchar_t);
    
    char enum_check(signed short);
    char enum_check(unsigned short);
    char enum_check(signed int);
    char enum_check(unsigned int);
    char enum_check(signed long);
    char enum_check(unsigned long);
    
    #if LONGLONG_EXITS
        char enum_check(signed long long);
        char enum_check(unsigned long long); 
    #endif
    
    char enum_check(float);
    char enum_check(double);
    char enum_check(long double);
    
    // 所有其他类型,都返回2
    SizeOverOne enum_check(...);
    
    template <typename T>
    class IsEnumT {
        public:
            enum {Yes= IsFundaT<T>::No &&
                !CompondT<T>::IsRefT &&
                !CompondT<T>::IsPtrT &&
                !CompondT<T>::IsPtrMemT &&
                sizeof(enum_check(ConsumeUDC<T>()))==1};
            enum {No=!Yes};
    };
    
    
    // 类类型处理
    template <typename T>
    class IsClassT {
        public:
            enum {Yes=IsFundaT<T>::No &&
                IsEnumT<T>::No &&
                !CompondT<T>::IsPtrT &&
                !CompondT<T>::IsRefT &&
                !CompondT<T>::IsArrayT &&
                !CompondT<T>::IsPtrMemT &&
                !CompondT<T>::IsFuncT};
            enum {No=!Yes};
    };
    
    // 处理所有类型的模板类
    template <typename T>
    class TypeT {
        public:
            enum {
                IsFundaT = IsFundaT<T>::Yes,
                IsPtrT = CompondT<T>::IsPtrT,
                IsRefT = CompondT<T>::IsRefT,
                IsArrayT = CompondT<T>::IsArrayT,
                IsFuncT = CompondT<T>::IsFuncT,
                IsPtrMemT = CompondT<T>::IsPtrMemT,
                IsEnumT = IsEnumT<T>::Yes,
                IsClassT = IsClassT<T>::Yes
            };
    };
    
    #endif
    

    main.cpp

    #include "typet.hpp"
    
    #include <iostream>
    
    class MyClass {};
    
    void myfunc() {}
    
    enum E {e1};
    
    
    // 使用类型调用
    template <typename T>
    void check() {
        if(TypeT<T>::IsFundaT) {
            std::cout << "IsFundaT";
        }else if(TypeT<T>::IsPtrT) {
            std::cout << "IsPtrT";
        }else if(TypeT<T>::IsRefT) {
            std::cout << "IsRefT";
        }else if(TypeT<T>::IsArrayT) {
            std::cout << "IsArrayT";
        }else if(TypeT<T>::IsFuncT) {
            std::cout << "IsFuncT";
        }else if(TypeT<T>::IsPtrMemT) {
            std::cout << "IsPtrMemT";
        }else if(TypeT<T>::IsEnumT) {
            std::cout << "IsEnumT";
        }else if(TypeT<T>::IsClassT) {
            std::cout << "IsClassT";
        }
        std::cout << std::endl;
    }
    
    // 使用实例调用
    template <typename T>
    void checkT(T) {
        check<T>();
        // 指针类型打印基础类型
        if(TypeT<T>::IsPtrT || TypeT<T>::IsPtrMemT) {
            check<typename CompondT<T>::BaseT>();
        }
    }
    
    int main(int argc, char* argv[]) {
        std::cout << "int:" << std::endl;
        check<int>();
    
        std::cout << "int&:" << std::endl;
        check<int&>();
    
        std::cout << "char[42]:" << std::endl;
        check<char[42]>();
    
        std::cout << "MyClass:" << std::endl;
        check<MyClass>();
    
        std::cout << "ptr to enum:" << std::endl;
        E* ptr = 0;
        checkT(ptr);
    
        std::cout << "42:" << std::endl;
        checkT(42);
    
        std::cout << "myfunc():" << std::endl;
        checkT(myfunc);
    
        std::cout << "memptr to array:" << std::endl;
        char (MyClass::* memptr) [] = 0;
        checkT(memptr);
        return EXIT_SUCCESS;
    }
    

    程序输出如下,


    image.png

    相关文章

      网友评论

          本文标题:C++11 自定义类型萃取器

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