//头文件
#include <iostream>
using namespace std;
template <typename T>
class Safe{
};
template <int N>
class Danger{
public:
char Block[N];
};
template <typename T, int N>
class Tricky{
public:
Tricky(){
cout << "Tricky" << endl;
}
virtual ~Tricky(){
cout << "~Tricky" << endl;
}
void no_body_here(Safe<T> = 3);//编译器解析时,会觉得此处可疑,但编译器会假设该参数“处于最理想的情况”(assume the best)
void inclass(){
Danger<N> no_boom_yet;
}
void error() { Danger<0> boom; }
void unsafe(T(*p)[N])
{
cout << typeid(p).name() << endl;
}
//VS2013 提示:
//error LNK2001: 无法解析的外部符号 "public: virtual class Safe<int> __thiscall
//Tricky<int,0>::suspect(void)" (?suspect@?$Tricky@H$0A@@@UAE?AV?$Safe@H@@XZ)
//---《C++ Template》解析:
//作为实例化类模板的结果,虚函数的定义可能被实例化了,但也可能没被实例化,这要依赖于具体的实现。
//实际上,许多实现都会实例化(虚函数)这个定义,因为“实现虚函数调用机制的内部结构”要求虚函数
//(的定义)作为链接实体存在
//PS:我还不理解 O(∩_∩)O~~
//virtual Safe<T> suspect();
//一个类型而已
struct Nested
{
};
#if 0
//匿名 union,被当做是成员看待,因此实例化模板时,会去实例化此匿名 union
union {
Danger<N> anonymous2;
int align;
Safe<T> anonymous;
//Danger<N> anonymous2;
};
#endif
Danger<N> annonymous3;
};
int _tmain(int argc, _TCHAR* argv[])
{
#if 0 //这里的代码和注释都是正确的,只是为了后面的调试才不用这的代码了
int (*a)[1] = { 0 };
//Tricky<int, 2> ok1;
//ok1.unsafe(a);//error C2664: “void Tricky<int,2>::unsafe(T (*)[2])”: 无法将参数 1 从“int (*)[1]”转换为“int (*)[2]”
Tricky<int, 1> ok;
ok.unsafe(a);//输出:int (*)[1] 这是啥类型,指向数组的指针?我想是的
#endif
#if 0 //这里的代码和注释都是正确的,只是为了后面的调试才不用这的代码了
//如果不调用 inclass/error 成员函数,则编译不产生任何提示,如果调用了呢,提示如下:
//warning C4200: 使用了非标准扩展 : 结构/联合中的零大小数组
//当 UDT 包含大小为零的数组时,无法生成复制构造函数或副本赋值运算符
// : 参见对正在编译的类 模板 实例化“Danger<0>”的引用
// : 编译类 模板 成员函数“void Tricky<int, 0>::inclass(void)”时
// : 参见对正在编译的函数 模板 实例化“void Tricky<int, 0>::inclass(void)”的引用
// : 参见对正在编译的类 模板 实例化“Tricky<int, 0>”的引用
//解析:
//当只定义 ok2 的时候,只是进行模板实例化声明,而未进行实例化定义(好像这样的实例化就叫延迟实例化吧),就是说,
//如果成员函数没调用,就不管这个成员函数有没有定义。当调用了成员函数后,就会去定义一个元素个数为0的数组,然后就产生这个提示了
Tricky<int, 0> ok2;
// ok2.inclass();
// ok2.error();
#endif
#if 0//有问题,没弄懂
//我这里只借用了类模板的Nested类型,却对匿名 union 的 Danger<N> anonymous2; 提示:warning C4200: 使用了非标准扩展 : 结构/联合中的零大小数组
//当 UDT 包含大小为零的数组时,无法生成复制构造函数或副本赋值运算符
//当然 Danger<N> annonymous3; 也有提示
//解析:
//这里对模板进行实例化了,实例化模板时,会去查询成员变量的定义,从而给出warning
Tricky<int, 0>::Nested nest;//不会有构造和析构函数的打印
//问题:没弄懂啊~~~
//当把 Tricky 模板中union处的#if 用#if 1时,会产生错误 error C2229: class“Tricky<int,0>”有非法的大小为零的数组(指向annonymous3)
//而把 Danger<N> anonymous2; 挪到前面去或者用#if 0时,则无error
#endif
system("pause");
return 0;
}
Danger<N> annonymous3; 是第三处测试加上去的