双十一前夕买的书到了,其中一本便是C++ Templates,书比较老了但依旧经典,周末的时候翻看了下,感觉挺好。今天在等待代码编译时,突发脑袋里面蹦出了一个疑问,虽然C++标准有规定,模板会被进行两次三阶段的编译,但是什么时候开始对模板进行编译呢(当我把博客写了一半之后发现C++ Templates一书中明确提到了实例化之前就进行语法检查,于是开始继续研究VS到底有多特立独行)?
于是我写下了下面的代码。
template <typename T>
void Test(T a)
{
T c
}
int main(int argc, char **argv)
{
return 0;
}
在VS中编译,顺利通过,就连一个警告都没有。
加上调用之后
template <typename T>VS开始报错,于是我得出了一个结论,函数模板会在实例化时才会被编译器处理,幸好,当我在将这个结论写在书上之后我又试了试g++。在g++中第一种写法的时候就开始报错。那么g++应该是在遇到模板本身的时候就开始对模板进行语法检查。但是这样的话,如果模板所在的文件被多个文件包含,那岂不是得进行很多次语法检查?VS的处理方式这时候看起来好像就更为妥当????
void Test(T a)
{
T c
}
int main(int argc, char **argv)
{
int a = 0;
Test(a);
return 0;
}
其实也不是,想象这样一个场景,在你使用VS时,你的模板所在的文件被很多文件包含,你突然想给之前定义的模板加点东西。加完之后开始编译。编译器正常的对所有包含了模板所在文件的文件进行重新编译(头文件被预处理器展开之后导致所有包含了该头文件的文件被改变),编译了一段时间之后终于编译到了实例化模板的文件,编译器开始处理模板,但是接下来却不顺利了,编译器报错了。你在之前更改模板的时候不小心引入了错误。。。。。。你又必须再次更改模板,所有包含了模板所在文件的文件又必须再次编译一遍。。。。。。。。如果用的是g++是不是就可以提早发现错误呢?(也许??反正测试效果蛮好的也不会出现下面的问题)
(此时发现C++ Templates明确提出)实例化之前就进行语法检查
继续看VS的特立独行
现在将代码改成这样
template <typename T>
void Test(T a)
{
asdadadadadadadadadadadadadadadadasd
}
int main(int argc, char **argv)
{
int a = 0;
Test();
return 0;
}
现在模板被调用了。VS总该去处理模板了吧,按照标准,应该先编译模板本身进行语法检查。但是你会发现它报的错误却是error c2780 "void Test(T)"应输入1个参数,却提供了0个。根据标准这是第二阶段的编译。。。。。
继续
template <typename T>
void Test(T a)
{
asdadadadadadadadadadadadadadadadasd
}
int main(int argc, char **argv)
{
int a = 0;
Test( a );
return 0;
}
这个时候VS才标准规定的报语法错误, error c2065 与 error c2143