以前大致看过模板元编程但是并没有深入进去
现在就拿比较小的Loki库研究了
本文主要涉及的是其头文件TypeMapIP.h
1.根据给定常量生成对等枚举变量
////////////////////////////////////////////////////////////////////////////////
// class template Int2Type
// Converts each integral constant into a unique type
// Invocation: Int2Type<v> where v is a compile-time constant integral
// Defines 'value', an enum that evaluates to v
////////////////////////////////////////////////////////////////////////////////
template <int v>
struct Int2Type
{
enum { value = v };
};
正如所说:v是一个编译期常量整数
2.类型重定义
////////////////////////////////////////////////////////////////////////////////
// class template Type2Type
// Converts each type into a unique, insipid type
// Invocation Type2Type<T> where T is a type
// Defines the type OriginalType which maps back to T
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct Type2Type
{
typedef T OriginalType;
};
举例子为:
Type2Type<vector<int> >::OriginalType v;
当前盖莫引擎就是这样使用链表的O(∩_∩)O~如下:
#include <loki/flex/flex_string.h>
typedef flex_string<char> engine_string;
#include <loki/yasli/yasli_vector.h>
template<class T>
struct vector_typedef
{
typedef yasli::vector<T,std::allocator<T> > type;
};
template<class T>
struct list_typedef
{
typedef yasli::vector<T,std::allocator<T> > type;
};
#endif
基本上是模板重定义
3.条件类型重定义
////////////////////////////////////////////////////////////////////////////////
// class template Select
// Selects one of two types based upon a boolean constant
// Invocation: Select<flag, T, U>::Result
// where:
// flag is a compile-time boolean constant
// T and U are types
// Result evaluates to T if flag is true, and to U otherwise.
////////////////////////////////////////////////////////////////////////////////
template <bool flag, typename T, typename U>
struct Select
{
typedef T Result;
};
template <typename T, typename U>
struct Select<false, T, U>
{
typedef U Result;
};
举例为:
Select<true,int,char>::Result r;
则r为int 类型
Seclet<false,int,char>::Result r
r为char类型
这样的例子基本上在所有模板元编程书上都可以看到
当然还有很多代码,比如DyObjLib库
4.检测对象是否为同一类型
template <typename T, typename U>
struct IsSameType
{
enum { value = false };
};
template <typename T>
struct IsSameType<T,T>
{
enum { value = true };
};
记得以前我看到这个的时候感觉实现的太巧妙了
5.Conversion模板
////////////////////////////////////////////////////////////////////////////////
// class template Conversion
// Figures out the conversion relationships between two types
// Invocations (T and U are types):
// a) Conversion<T, U>::exists
// returns (at compile time) true if there is an implicit conversion from T
// to U (example: Derived to Base)
// b) Conversion<T, U>::exists2Way
// returns (at compile time) true if there are both conversions from T
// to U and from U to T (example: int to char and back)
// c) Conversion<T, U>::sameType
// returns (at compile time) true if T and U represent the same type
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
Conversion模板指出了给定2个类型之间的转换关系
具体源码为:
template <class T, class U>
struct Conversion
{
typedef Private::ConversionHelper<T, U> H;
#ifndef __MWERKS__
enum { exists = sizeof(typename H::Small) == sizeof((H::Test(H::MakeT()))) };
#else
enum { exists = false };
#endif
enum { exists2Way = exists && Conversion<U, T>::exists };
enum { sameType = false };
};
_MWERKS是什么宏定义
先不管它
再看其特化形式
template <class T>
struct Conversion<T, T>
{
enum { exists = 1, exists2Way = 1, sameType = 1 };
};
template <class T>
struct Conversion<void, T>
{
enum { exists = 0, exists2Way = 0, sameType = 0 };
};
template <class T>
struct Conversion<T, void>
{
enum { exists = 0, exists2Way = 0, sameType = 0 };
};
template <>
struct Conversion<void, void>
{
public:
enum { exists = 1, exists2Way = 1, sameType = 1 };
};
这里给定了4种特化形式
3个涉及void类型
1个涉及类型相同
可以看出:
如果2个对象类型相同则枚举变量sameType必定为真
关于枚举变量exists
如果其为真则说明T类型可以转化为U类型(比如子类到父类)
关于变量exists2Way表达的是U,T类型是否可以双向转化(比如int,和long类型)
6.继承关系的鉴别
////////////////////////////////////////////////////////////////////////////////
// class template SuperSubclass
// Invocation: SuperSubclass<B, D>::value where B and D are types.
// Returns true if B is a public base of D, or if B and D are aliases of the
// same type.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
如果B类型是D类型的公共父类则结果为真
否则为假
代码为:
template <class T, class U>
struct SuperSubclass
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType) };
// Dummy enum to make sure that both classes are fully defined.
enum{ dontUseWithIncompleteTypes = ( sizeof (T) == sizeof (U) ) };
};
template <>
struct SuperSubclass<void, void>
{
enum { value = false };
};
template <class U>
struct SuperSubclass<void, U>
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile void*>::exists &&
!::Loki::Conversion<const volatile void*, const volatile void*>::sameType) };
// Dummy enum to make sure that both classes are fully defined.
enum{ dontUseWithIncompleteTypes = ( 0 == sizeof (U) ) };
};
template <class T>
struct SuperSubclass<T, void>
{
enum { value = (::Loki::Conversion<const volatile void*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType) };
// Dummy enum to make sure that both classes are fully defined.
enum{ dontUseWithIncompleteTypes = ( sizeof (T) == 0 ) };
};
其几种特化形式都与void类型有关
再看其value描述:
enum { value = (::Loki::Conversion<const volatile void*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType) };
当void*可以转化为T*同时T*类型不为void*时则value为真
enum{ dontUseWithIncompleteTypes = ( 0 == sizeof (U) ) };
该枚举变量时防止类型变量存在不完全类型
可以看出在模板元编程中可以使用enum变量来处理和预报错误
给定一个例子
#include <iostream>
#include <string>
#include <Loki/TypeManIP.h>
#include <typeinfo>
class A;
int main()
{
std::cout<<Loki::SuperSubclass<void,A>::dontUseWithIncompleteTypes<<std::endl;
system("PAUSE");
return EXIT_SUCCESS;
}
编译器会报出一个194 E:\c++header\Loki\TypeManIP.h invalid application of `sizeof' to incomplete type `A' 错误
7.对象严格继承关系的鉴别
////////////////////////////////////////////////////////////////////////////////
// class template SuperSubclassStrict
// Invocation: SuperSubclassStrict<B, D>::value where B and D are types.
// Returns true if B is a public base of D.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
template<class T,class U>
struct SuperSubclassStrict
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType &&
!::Loki::Conversion<const volatile T*, const volatile U*>::sameType) };
// Dummy enum to make sure that both classes are fully defined.
enum{ dontUseWithIncompleteTypes = ( sizeof (T) == sizeof (U) ) };
};
template<>
struct SuperSubclassStrict<void, void>
{
enum { value = false };
};
template<class U>
struct SuperSubclassStrict<void, U>
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile void*>::exists &&
!::Loki::Conversion<const volatile void*, const volatile void*>::sameType &&
!::Loki::Conversion<const volatile void*, const volatile U*>::sameType) };
// Dummy enum to make sure that both classes are fully defined.
enum{ dontUseWithIncompleteTypes = ( 0 == sizeof (U) ) };
};
template<class T>
struct SuperSubclassStrict<T, void>
{
enum { value = (::Loki::Conversion<const volatile void*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType) };
// Dummy enum to make sure that both classes are fully defined.
enum{ dontUseWithIncompleteTypes = ( sizeof (T) == 0 ) };
};
以上是代码段
当然以上2种类型检测都不能处理私有继承的关系
下面是简单的测试例子:
#include <iostream>
#include <string>
#include <Loki/TypeManIP.h>
#include <typeinfo>
class B
{};
class D : public B
{
};
int main()
{
std::cout<<LOKI_SUPERSUBCLASS(B,D)<<std::endl;
std::cout<<LOKI_SUPERSUBCLASS(D,B)<<std::endl;
std::cout<<LOKI_SUPERSUBCLASS(B,int)<<std::endl;
std::cout<<LOKI_SUPERSUBCLASS(long,D)<<std::endl;
system("PAUSE");
return EXIT_SUCCESS;
}
TypemanIp看完了
8.最后我给出我看到的另外一种检测对象是否含有Vtable的检测手法:
template<class T>
struct IsVObjImpl {
struct IA : public T {
int m;
};
struct IB : public T {
virtual void F( );
int m;
};
enum { v = (sizeof(IA)==sizeof(IB)) };
};
首先定义2个类对象他们都继承于给定类型
然后一个还有Vtable
一个不含有Vtable
之后侦测其size是否相同
可以看出vtable是不占有子类大小的
测试例子如下:
#include <iostream>
template<class T>
struct IsVObjImpl
{
struct IA : public T {
int m;
};
struct IB : public T {
virtual void F( );
int m;
};
enum { v = (sizeof(IA)==sizeof(IB)) };
};
class A
{
virtual void v(){}
};
class B
{
void v(){}
};
int main()
{
std::cout<<IsVObjImpl<A>::v<<std::endl;
std::cout<<IsVObjImpl<B>::v<<std::endl;
system("PAUSE");
return EXIT_SUCCESS;
}
9.一些其他的对象类型测试手法:
// Check if type is const
template <class T>
struct DoIsConst {
enum { v=0 };
};
template <class T>
struct DoIsConst<const T> {
enum { v=1 };
};
template <class T> // Should this be needed?
struct DoIsConst<const T&> {
enum { v=1 };
};
template <class T> // Should this be needed?
struct DoIsConst<const T*> {
enum { v=1 };
};
/////////////////////////////////////////
// Check if type is a ref or not
template <class T>
struct DoIsRef {
enum { v=0 };
};
template <class T>
struct DoIsRef<T&> {
enum { v=1 };
};
/////////////////////////////////////////
// Check if type is a pointer or not
template <class T>
struct DoIsPointer {
enum { v=0 };
};
template <class T>
struct DoIsPointer<T*> {
enum { v=1 };
};
这些东西都源于DyObj
A C++ framework for binary reusable objects, or plugins. It enables exposing and sharing run-time type information for C++ classes
当然boost中可定可以找到类型代码的
应该在type_traits中吧?