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

2022-01-19  本文已影响0人  FredricZhu

本文是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
上一篇 下一篇

猜你喜欢

热点阅读