作者Scott Meyers在《Effective STL》书里以条款的方式继续他的C++科普事业。在第六条款,一开始就抛出一个看似很正常的语句
ifstream datafile ( "ins.dat" );
list <int > data ( istream_iterator <double >( datafile),
istream_iterator< double >());
本意是通过输入流从ins.dat文件读取一系列整数并存到list<int>中,编译可以通过,但是运行期什么也不发生。Meyers通过枚举函数参数
声明的方式一步步揭开编译器之所以会错误解析。
假设我们要声明一个函数,他的功能是返回int 传入参数是 double类型值,一般是这样做的:
int foo(double d);
其实,在声明对象的时候,比如 int a=3;int b=a;可以写作int b=int(a);或者int b=(int)a;
同样的,编译器允许我们参数声明的时候加上括号
int foo(double (d)); //编译器自动去除括号。
更近一步地,可以去除变量名,
int foo(double);
以上三种函数声明,一般的程序员应该都知道。
下面这三种函数声明方式可就有点复杂了。
假设我要声明一个函数foo ,其返回值为int,入参是一个函数指针pf,pf的返回值为double 无入参。
我们可以这么声明。
typedef double (*PF)();
int foo(PF pf ); //比较常见的声明方式。
//等价于
int foo(double (*pf)()); // 只是没用别名
也可以使用非指针语法形式声明pf
int foo(double pf() );
这样以来,pf参数就可以省略了。变成
int foo(double()); // 如果是int foo(double)就是传一个变量,加上"()"就是指针了.看出区别了吗?
看出来了吗,data变量现在被编译器解析成函数声明啦!!!
这行代码声明了一个函数data,它的返回类型是list<int>。这个函数data带有两个参数:
● 第一个参数叫做dataFile。它的类型是istream_iterator<int>。dataFile左右的括号是多余的而且被忽略。
● 第二个参数没有名字。它的类型是指向一个没有参数而且返回istream_iterator<int>的函数的指针。
我用vs2012编译会有警告,说这个是未调用原型函数。
下面如果继续使用data就会报错了,说是未定义变量。
那要怎么能让他编译通过呢,给每个参数加个大括号,表明这个是一个值。
源代码如下:
#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
using namespace std;
int main ( int, char** )
{
ifstream datafile("E:\\CPPDemo\\ins.txt");
vector<double> data( (istream_iterator<double>(datafile)),(istream_iterator<double>()));
for each ( auto elem in data )
{
cout<<elem<<endl;
}
system("pause");
return 0;
}