深度探索c++对象模型之template的错误报告

      考虑下面的template声明【里面有不少错误】:

template< class T >
class Mumble
{
public$: //第一处错误,非法标识符$
  Mumble( T t=1024 ) //第二处错误,t被初始化1024,但如果我们给mumble绑定的是char呢?
  :_t(t) //第三处错误,_t并不是哪一个mumble中的成员,tt才是。这种错误一般会在类型检查这个阶段查找出来。每一个名称必须绑定在一个定义身上,要不就会被判定错误!
  {
     if( tt != t ) //第四处错误, !=运算符有可能还没有定义好【视T的真正绑定类型来定】,和第二点一样,只有template的各个实体才能诊断出来。
       throw ex ex; //第五处错误,非法标识符ex ex;这种错误会在编译时起的解析阶段被发现,c++语言中一个合法的句子不允许一个标识符后面紧跟一个标识符。
    }
private:
  T tt;
};
在一个nontemplate class声明中,这五个错误会在编译时期就能查出来。但template class却不同,举个例子,所有与类型有关的检验,如果牵扯到template参数,都必须延迟到真正的具现【instantiation】操作时才发生,也就是说,第二处错误与第四处错误会在每个具现【instantiation】操作时才能被检查出来,其结果会因为不同的实际绑定类型而不同,比如:

Mumble<int> m; //合法的
则第二处与第四处就不是错误,但如果是

Mumble<int*> pm; //非法的
那么第四处依然正确,但第二处肯定是错误!因为在c++中,不允许将一个除了0之外的整数常量赋值给指针。

      那么,什么样的错误会在编译器处理template声明时被找出来?这里有一部分和template的处理策略有关。cfront对template的处理是完全解析【parse】,但不做类型检验,只有在每一个具现【instantiation】操作时才做类型检验,所以在这种parse策略之下,所有的语汇错误和解析错误都会在处理template声明时被找出来。

      语汇分析器【lexical analyzer】会在第一处错误那里捕捉到一个非法标识符,解析器【parser】会这样标识它:(  public$: // caught ),表示这是一个不合法的卷标【label】,但解析器不会把“对一个未命名的member成员做出参考操作”视为错误,所以第三处错误并不归解析器负责,但解析器仍然会抓住第五处错误。

      在一个十分普遍的替代策略中,template声明被收集为一系列的“lexical tokens”,而parsing操作延迟到有真正具现【instantiation】操作时才开始:每当看到一个instantiation,相关的token就会被推往parser,然后调用类型检验查找有无错误等等;面对先前出现的那个template声明,“lexical tokenizing”会指出什么错误吗?事实上很少,只有第一处错误那里的非法标识符会被找出,其余的template声明都会被解析为合法的tokens并收集起来!

      Nonmember和member template function在具现【instantiation】发生之前也没有做到完全的类型检验,这导致某些十分离谱的错误竟然可以编译通过,例如下面这个:

template<class type>
class Foo
{
public:
  Foo();
  type val();
  void val(type v);
private:
  type _val;
}; //以上这些没啥问题
...
template<class type>
double Foo<type>::helle(){ return this->world; } //错误在这里!看里面的hello和world,我们可有在Foo里面声明?
不论是cfront还是Sun编译器亦或borland,都不会对上面的代码产生怨言!


      再说一次,上面的策略,都是编译器设计者自己的决定,template facility并没有说不允许对template声明的类型部分有更严格的检查,当然,其实这样的错误可以在编译时起发现,只不过大家懒得这么做罢了。





发布了53 篇原创文章 · 获赞 113 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章