istream_iterator使用中常见的错误说明
(转载请注明来源于金庆的专栏)
在 http://www.cppblog.com/hdqqq/archive/2007/12/11/38216.html
的评论中看到一段istream_iterator的使用代码,
读取文件test.txt,将其中字符串输入到一个vector。
以下原代码不能通过编译:
ifstream ifs("test.txt");
istream_iterator<string> ibeg(ifs);
istream_iterator<string> iend();
vector<string> vec(ibeg, iend);
对于vec的构造编译出错:
error: no matching function for call to `std::vector<std::string, std::allocator<std::string> >::vector(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>&, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t> (&)())'
原来它把iend当作了一个函数。去掉iend后面的括号就行了:
#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
ifstream ifs("test.txt");
istream_iterator<string> ibeg(ifs);
istream_iterator<string> iend;
vector<string> vec(ibeg, iend);
copy(vec.begin(), vec.end(),
ostream_iterator<string>(cout, "/n"));
return 0;
}
就像在copy函数中一样,并不需要定义ibeg, iend, 应该可以在vector的构造函数中嵌入,如下:
vector<string> vec(istream_iterator<string>(ifs),
istream_iterator<string>);
以上代码当在copy中调用vec.begin(), vec.end()时,就会编译报错:
error: request for member `begin' in `vec', which is of non-class type `std::vector<std::string, std::allocator<std::string> > ()(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>)'
error: request for member `end' in `vec', which is of non-class type `std::vector<std::string, std::allocator<std::string> > ()(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>)'
看来编译器将vec当作了一个函数,而不是一个vector类。
其中istream_iterator<string>(ifs)
的括号被编译器忽略了,成为
vector<string> vec(istream_iterator<string> ifs,
istream_iterator<string>);
等同于:
vector<string> fun(istream_iterator<string> x,
istream_iterator<string> y);
就像在加减乘除中用括号指定运算顺序一样,这里也要用括号将构造的临时参数括起来,访止编译器将它们误解为函数中的参数声明。
同时还要修正一个错误,vec构造函数中的第二个参数构造是错误的,应该加个括号构造一个临时变量。不然对
istream_iterator<string>);
报错:
error: expected primary-expression before ')' token
因为它只是一个类型声明,而不是一个基本表达式(primary-expression)。
正确的方法如下:
vector<string> vec((istream_iterator<string>(ifs)),
istream_iterator<string>());
或
vector<string> vec((istream_iterator<string>(ifs)),
(istream_iterator<string>()));
提示:不管需不需要,稍微复杂一点的表达式都用括号括起来。免得人阅读时出错,或者编译器理解时出错。
ibeg, iend的定义可以合为一行,可能比内嵌式表达方法更清晰:
istream_iterator<string> ibeg(ifs), iend;
vector<string> vec(ibeg, iend);
STL中模板的大量使用,使得编译器的报错不知所云,让人对STL的应用望而却步。学习STL不仅要掌握STL中各种容器类,迭代器,算法,同时还要熟悉编译器常见的错误报告。
(转载请注明来源于金庆的专栏)
在 http://www.cppblog.com/hdqqq/archive/2007/12/11/38216.html
的评论中看到一段istream_iterator的使用代码,
读取文件test.txt,将其中字符串输入到一个vector。
1. 错误原码
以下原代码不能通过编译:
ifstream ifs("test.txt");
istream_iterator<string> ibeg(ifs);
istream_iterator<string> iend();
vector<string> vec(ibeg, iend);
对于vec的构造编译出错:
error: no matching function for call to `std::vector<std::string, std::allocator<std::string> >::vector(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>&, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t> (&)())'
原来它把iend当作了一个函数。去掉iend后面的括号就行了:
2. 正确的完整代码
#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
ifstream ifs("test.txt");
istream_iterator<string> ibeg(ifs);
istream_iterator<string> iend;
vector<string> vec(ibeg, iend);
copy(vec.begin(), vec.end(),
ostream_iterator<string>(cout, "/n"));
return 0;
}
3. 直接内嵌出错
就像在copy函数中一样,并不需要定义ibeg, iend, 应该可以在vector的构造函数中嵌入,如下:
vector<string> vec(istream_iterator<string>(ifs),
istream_iterator<string>);
以上代码当在copy中调用vec.begin(), vec.end()时,就会编译报错:
error: request for member `begin' in `vec', which is of non-class type `std::vector<std::string, std::allocator<std::string> > ()(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>)'
error: request for member `end' in `vec', which is of non-class type `std::vector<std::string, std::allocator<std::string> > ()(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>)'
看来编译器将vec当作了一个函数,而不是一个vector类。
其中istream_iterator<string>(ifs)
的括号被编译器忽略了,成为
vector<string> vec(istream_iterator<string> ifs,
istream_iterator<string>);
等同于:
vector<string> fun(istream_iterator<string> x,
istream_iterator<string> y);
4. 访止编译器误解
就像在加减乘除中用括号指定运算顺序一样,这里也要用括号将构造的临时参数括起来,访止编译器将它们误解为函数中的参数声明。
同时还要修正一个错误,vec构造函数中的第二个参数构造是错误的,应该加个括号构造一个临时变量。不然对
istream_iterator<string>);
报错:
error: expected primary-expression before ')' token
因为它只是一个类型声明,而不是一个基本表达式(primary-expression)。
正确的方法如下:
vector<string> vec((istream_iterator<string>(ifs)),
istream_iterator<string>());
或
vector<string> vec((istream_iterator<string>(ifs)),
(istream_iterator<string>()));
提示:不管需不需要,稍微复杂一点的表达式都用括号括起来。免得人阅读时出错,或者编译器理解时出错。
5. 另一种简化方法
ibeg, iend的定义可以合为一行,可能比内嵌式表达方法更清晰:
istream_iterator<string> ibeg(ifs), iend;
vector<string> vec(ibeg, iend);
6. 结论
STL中模板的大量使用,使得编译器的报错不知所云,让人对STL的应用望而却步。学习STL不仅要掌握STL中各种容器类,迭代器,算法,同时还要熟悉编译器常见的错误报告。