#if 0
在上一章里面讨论了代码的自动生成机制,经常会遇到根据不同的类型选择不同的操
作的情况,也就是静态分派的问题。这就需要有一种机制用来识别不同的类型,在本章里
面将会系统的讨论C++里面可用的类型识别问题。
最常见的有下面几种:
(1)根据模板参数需要精确匹配类型来识别类型
(2)根据隐式自动转型来判断类型是否可以自动转型,从而可以判断是某个基类的派生
类。
(3)给每一个类型都追加一个额外的模板参数用来表示不同的类型,一般都是用不同的
数字映射为不同的类型来实现类型识别的,前面讨论的可以有重复类型的scatter代码产生
器就采用了这种方法来识别不同的类型的。
在这一章里面将会分别讨论上面的三种情况的一般应用:
#endif
#ifdef CODE1//g++ -DCODE1 thisfile.cpp
//采用方法(1)来识别不同的类型
#include <iostream>
#include <string>
#include <complex>
template <class T>struct traits;
template <> struct traits<char > {static const char*name(){return "char ";}};
template <> struct traits<int > {static const char*name(){return "int ";}};
template <> struct traits<short > {static const char*name(){return "short ";}};
template <> struct traits<long > {static const char*name(){return "long ";}};
template <> struct traits<float > {static const char*name(){return "float ";}};
template <> struct traits<double> {static const char*name(){return "double";}};
template <> struct traits<std::string>
{
static const char*name(){return "std::string";}
};
template <> struct traits<std::complex<float > >
{
static const char*name(){return "std::complex<float>";}
};
template <> struct traits<std::complex<double> >
{
static const char*name(){return "std::complex<double>";}
};
int main()
{
std::cout<<"char :["<<traits<char >::name()<<"]"<<std::endl;
std::cout<<"int :["<<traits<int >::name()<<"]"<<std::endl;
std::cout<<"short :["<<traits<short >::name()<<"]"<<std::endl;
std::cout<<"long :["<<traits<long >::name()<<"]"<<std::endl;
std::cout<<"float :["<<traits<float >::name()<<"]"<<std::endl;
std::cout<<"double:["<<traits<double>::name()<<"]"<<std::endl;
std::cout<<"std::string:["<<traits<std::string>::name()<<"]"<<std::endl;
std::cout<<"std::complex<float >:["<<traits<std::complex<float > >::name()<<"]"<<std::endl;
std::cout<<"std::complex<double>:["<<traits<std::complex<double> >::name()<<"]"<<std::endl;
return 0;
}
#endif//CODE1
//该程序的运行结果:
/*******************************************************************************
char :[char ]
int :[int ]
short :[short ]
long :[long ]
float :[float ]
double:[double]
std::string:[std::string]
std::complex<float >:[std::complex<float>]
std::complex<double>:[std::complex<double>]
*******************************************************************************/
#if 0
从CODE1的运行结果可以看出:已经成功的分辨出了各个不同的类型。但是我们还是可
以看出为了能够分辨出不同的类型需要编写大量的代码,对于基础类型这是不可避免的,
但是值得庆幸的是C++里面的基本类型是有限的,所以作为一个库的编写者来说完全可采用
穷举的方法来完成的。但是我们可以看出针对于CODE1中的std::complex<float>和std::
complex<double>来说,它们实际上是一种模板代码,不同的模板参数完全可产生出无数的
类型出来,对于这样的模板类型来说,采用穷举的方法恐怕就不行了。当然这里的复数类
一般就只会使用float和double来作为模板参数,但是对于判断某个型别是否是某个模板类
型以及判断某个类型是否是某个模板类型的派生类就力不足心了。为了便于讨论这个问题
,我们假定这个模板类型只有一个模板参数。参见下面的代码:
#endif
#ifdef CODE_NOTE
//某个模板类
template <class T>struct Template{};
//某个模板类的派生类
template <class T>struct Derived:public Template<T>{};
#endif//CODE_NOTE
#if 0
对于上面的Template模板类来说同样可以采用CODE1中的方案来实现类型识别的,参看
CODE2中的测试代码:
#endif
#ifdef CODE2//g++ -DCODE2 thisfile.cpp
#include <iostream>
#include <string>
#include <complex>
//某个模板类
template<class T>struct Template{};
//识别这个模板类的方法:
template <class T> struct traits{static const char*name(){return "Is not kind of Template";}};
template <class T> struct traits<Template<T> >{static const char*name(){return "Is kind of Template";}};
template <class T> struct traits<std::complex<T> >{static const char*name(){return "Is kind of std::complex";}};
int main()
{
std::cout << "char :[" << traits<Template<char > >::name() << "]" << std::endl;
std::cout << "int :[" << traits<Template<int > >::name() << "]" << std::endl;
std::cout << "short :[" << traits<Template<short > >::name() << "]" << std::endl;
std::cout << "long :[" << traits<Template<long > >::name() << "]" << std::endl;
std::cout << "float :[" << traits<Template<float > >::name() << "]" << std::endl;
std::cout << "double:[" << traits<Template<double> >::name() << "]" << std::endl;
std::cout << "std::string:[" << traits<Template<std::string> >::name() << "]" << std::endl;
std::cout << "std::complex<float> :[" << traits<std::complex<float > >::name() << "]" << std::endl;
std::cout << "std::complex<double>:[" << traits<std::complex<double> >::name() << "]" << std::endl;
return 0;
}
#endif//CODE2
//该程序的运行结果:
/*******************************************************************************
char :[Is kind of Template]
int :[Is kind of Template]
short :[Is kind of Template]
long :[Is kind of Template]
float :[Is kind of Template]
double:[Is kind of Template]
std::string:[Is kind of Template]
std::complex<float> :[Is kind of std::complex]
std::complex<double>:[Is kind of std::complex]
*******************************************************************************/
#if 0
从CODE2的运行结果可以看出:我们已经成功的识别出了同一个模板类实例化出来的所
有的类型。现在我们就来考虑一下如何识别出某个模板类的派生类的问题,也就前面提到
的Derived类型的识别问题。对于这种问题就不可能用前面第一种方法来识别了。这个时候
就是第二种识别方法隆重登场的时候了。参见CODE3的代码:
#endif
#ifdef CODE3//g++ -DCODE3 thisfile.cpp
#include <iostream>
#include <string>
#include <complex>
//某个模板类
template <class T>struct Template{};
//另一个模板类
template <class T>struct AnotherTemplate{};
//某个模板类的派生类,可以有无数种
struct Derived1:public Template<char >{};
struct Derived2:public Template<int >{};
struct Derived3:public Template<short >{};
struct Derived4:public Template<long >{};
struct Derived5:public Template<float >{};
struct Derived6:public Template<double>{};
struct Derived7:public Template<std::string>{};
struct Derived8:public Template<std::complex<float > >{};
struct Derived9:public Template<std::complex<double> >{};
//考虑到这种情况必须采用一种映射关系,将所有的Template模板类的派生类都映射成为
//Template类型,注意哦,这里是映射而不是转型哦!映射到了Template类型之后再采用
//比较这个类型和参数类型的尺寸的方法来实现识别功能,具体代码如下:
template <class T,template<class>class TemplateType>
class is_kind_of
{
//定义一个类型来表示任意类型
typedef char AnyType;
//定义一个类型来表示指定的类型
class SpecifiedType {char unnamed[2];};
//完成任意类型映射成为AnyType的功能
static AnyType Map(...);
//完成指定模板类型映射成为SpecifiedType的功能
//这里还使用了函数传递参数的时候隐式转型的能力
template<class PT>
static SpecifiedType Map(TemplateType<PT>);
public:
//通过计算映射之后的两个类型的尺寸来识别类型
enum{
//传递参数的时候让编译器来自动选择合适的Map函数以完成类型映射功
//能
yes=(sizeof(Map(T()))==sizeof(SpecifiedType)),
no =(sizeof(Map(T()))==sizeof(AnyType))
};
};
//下面是测试代码
int main()
{
std::cout << "Derived1 is kind of Template? " << is_kind_of<Derived1,Template>::yes << std::endl;
std::cout << "Derived2 is kind of Template? " << is_kind_of<Derived2,Template>::yes << std::endl;
std::cout << "Derived3 is kind of Template? " << is_kind_of<Derived3,Template>::yes << std::endl;
std::cout << "Derived4 is kind of Template? " << is_kind_of<Derived4,Template>::yes << std::endl;
std::cout << "Derived5 is kind of Template? " << is_kind_of<Derived5,Template>::yes << std::endl;
std::cout << "Derived6 is kind of Template? " << is_kind_of<Derived6,Template>::yes << std::endl;
std::cout << "Derived7 is kind of Template? " << is_kind_of<Derived7,Template>::yes << std::endl;
std::cout << "Derived8 is kind of Template? " << is_kind_of<Derived8,Template>::yes << std::endl;
std::cout << "Derived9 is kind of Template? " << is_kind_of<Derived9,Template>::yes << std::endl;
std::cout << "Derived1 is kind of AnotherTemplate? " << is_kind_of<Derived1,AnotherTemplate>::yes << std::endl;
std::cout << "Derived2 is kind of AnotherTemplate? " << is_kind_of<Derived2,AnotherTemplate>::yes << std::endl;
std::cout << "Derived3 is kind of AnotherTemplate? " << is_kind_of<Derived3,AnotherTemplate>::yes << std::endl;
std::cout << "Derived4 is kind of AnotherTemplate? " << is_kind_of<Derived4,AnotherTemplate>::yes << std::endl;
std::cout << "Derived5 is kind of AnotherTemplate? " << is_kind_of<Derived5,AnotherTemplate>::yes << std::endl;
std::cout << "Derived6 is kind of AnotherTemplate? " << is_kind_of<Derived6,AnotherTemplate>::yes << std::endl;
std::cout << "Derived7 is kind of AnotherTemplate? " << is_kind_of<Derived7,AnotherTemplate>::yes << std::endl;
std::cout << "Derived8 is kind of AnotherTemplate? " << is_kind_of<Derived8,AnotherTemplate>::yes << std::endl;
std::cout << "Derived9 is kind of AnotherTemplate? " << is_kind_of<Derived9,AnotherTemplate>::yes << std::endl;
return 0;
}
#endif//CODE3
//该程序的运行结果如下:
/*******************************************************************************
Derived1 is kind of Template? 1
Derived2 is kind of Template? 1
Derived3 is kind of Template? 1
Derived4 is kind of Template? 1
Derived5 is kind of Template? 1
Derived6 is kind of Template? 1
Derived7 is kind of Template? 1
Derived8 is kind of Template? 1
Derived9 is kind of Template? 1
Derived1 is kind of AnotherTemplate? 0
Derived2 is kind of AnotherTemplate? 0
Derived3 is kind of AnotherTemplate? 0
Derived4 is kind of AnotherTemplate? 0
Derived5 is kind of AnotherTemplate? 0
Derived6 is kind of AnotherTemplate? 0
Derived7 is kind of AnotherTemplate? 0
Derived8 is kind of AnotherTemplate? 0
Derived9 is kind of AnotherTemplate? 0
*******************************************************************************/
#if 0
从CODE3的运行结果可以看出:我们已经成功的实现了判断某个型别是否是某个模板类
的派生类或者是直接实例化的类的能力。因此我们就可以在自己编写代码的时候利用这些
功能来实现静态分派的能力。
至于第三种方法已经在前面的章节中讨论过了。根据索引号访问scatter产生的代码的
同类型变量的方法就是采用了第三种方法。
到目前为止,已经讨论了我所知道的C++里面的类型识别的一般方法。具体如何应用就要
看您的发挥了。我编写的撤销和重做库中就采用了这里的方法来识别简单类型和复合类型的。
#endif
C++自动化(模板元)编程基础与应用(6)
最新推荐文章于 2024-09-03 09:47:53 发布