本文是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
网友评论