首页 > 代码库 > C++编译器最烦人的分析机制

C++编译器最烦人的分析机制



下面这行代码声明了一个带double参数并返回int的函数:

int f(double d);

下面这行做了同样的事情,参数d两边的括号是多余的,会被忽略:

int f(double (d));

下面这行声明了同样的函数,只是它省略了参数名称:

int f(double);

这三种形式除了第二种,我们应该都很熟悉。

下面我们在看三个函数声明。第一个声明了一个函数g,它的参数是一个指向不带任何参数的函数的指针,该函数返回double值:

int g(double (*pf)());

有另外一种方式可表示同样的意思。唯一的却别是,pf用非指针的形式来声明(这种形式在CC++中都有效):

int g(double pf());

跟通常一样,参数名称可以省略,因此下面是g的第三种声明,其中参数名pf被省略了:

int g(double ());

请注意围绕参数名的括号(比如对f的第二个声明中的d)与独立的括号的区别。围绕参数名的括号被忽略,而独立的括号则表示参数列表的存在;它们说明存在一个函数指针参数。熟悉了上面的声明后,我们来看下面的问题:

假设我们有一个存有整数(int)的文件,你想把这些整数拷贝到一个list中。下面是很合理的一种做法:

ifstream dataFile(“ints.dat”);

list<int> data(istream_iterator<int>(dataFile),istream_iterator<int>());

这段代码可以通过编译,但是在运行时,它什么也不会做。它不会从文件中读取任何数据,它不会创建list。这是因为第二条语句并没有声明一个list,也没有调用构造函数。它所做的是下面的事情:

它声明了一个函数data,其返回值是list<int>data函数有两个参数:

第一个参数的名称是dataFile。它的类型是istream_iterator<int>dataFile两边的括号会被忽略。

第二个参数没有名称。它的类型是指向不带参数的函数的指针,该函数返回一个istream_iterator<int>

虽然令人吃惊,但却与C++中的一条普遍规律相符,即尽可能地解释为函数声明。再看下面的一种错误:

class Widget{ … };//假定Widget有默认构造函数

Widget w();

它没有声明名为wWidget,而是声明了一个名为w的函数,该函数不带任何参数,并返回一个Widget

我们想用文件的内容初始化list<int>对象,现在我们已经知道必须绕过某一种分析机制,剩下的事情就简单了。把形式参数的声明用括号括起来是非法的,但给函数参数加上括号却是合法的,所以通过增加一对括号,我们强迫编译器按我们的方式来工作:

list<int>data((istream_iterator<int>(dataFile)),istream_iterator<int>());

不幸的是,并不是所有恶编译器都知道这一点。更好的方式是在对data的声明中避免使用匿名的istream_iterator<int>对象(尽管使用匿名对象是一种趋势),而是给这些迭代器一个名称。下面的代码应该总是可以工作的:

ifstream dataFile(“ints.dat”);

istream_iterator<int>dataBegin(dataFile);

istream_iterator<int> dataEnd;

list<int> data(dataBegin,dataEnd);