下面的片段从中读取三个整数std::cin
; 它写入两个numbers
并丢弃第三个:
std::vector<int> numbers(2);
copy_n(std::istream_iterator<int>(std::cin), 2, numbers.begin());
Run Code Online (Sandbox Code Playgroud)
我希望代码能够准确地读取两个整数std::cin
,但事实证明这是一个正确的,符合标准的行为.这是标准中的疏忽吗?这种行为的理由是什么?
从C++ 03标准中的24.5.1/1开始:
在构造之后,每次使用++时,迭代器都会读取并存储一个值
T
.
所以在上面的代码中,在调用时,流迭代器已经读取了一个整数.从那时起,算法中迭代器的每次读取都是预读,从而产生从先前读取缓存的值.
下一个标准的最新草案n3225似乎没有任何变化(24.6.1/1).
在相关的说明中,参考istream_iterator(istream_type& s)
构造函数的当前标准的24.5.1.1/2 读取
效果:初始化
in_stream
为s
.value
可以在施工期间或第一次参考时初始化.
重点是" value
可以初始化......"而不是" 应该初始化".这听起来与24.5.1/1相矛盾,但也许这应该是一个自己的问题.
我构建了一个最小的工作示例来显示我使用STL迭代器遇到的问题.我正在使用istream_iterator
以下内容读取floats
s(或其他类型)std::istream
:
#include <iostream>
#include <iterator>
#include <algorithm>
int main() {
float values[4];
std::copy(std::istream_iterator<float>(std::cin), std::istream_iterator<float>(), values);
std::cout << "Read exactly 4 floats" << std::endl; // Not true!
}
Run Code Online (Sandbox Code Playgroud)
这将读取所有可能的floats
s,直到EOF为values
固定大小,4,所以现在显然我想限制范围以避免溢出并准确读取/最多4个值.
使用更多"正常"迭代器(即RandomAccessIterator),提供begin+4
的不是你要做的结束:
std::copy(begin, begin+4, out);
Run Code Online (Sandbox Code Playgroud)
准确阅读4个元素.
如何做到这一点std::istream_iterator
?显而易见的想法是将呼叫更改std::copy
为:
std::copy(std::istream_iterator<float>(std::cin), std::istream_iterator<float>(std::cin)+4, values);
Run Code Online (Sandbox Code Playgroud)
但(相当可以预见)这不编译,没有候选人operator+
:
g++ -Wall -Wextra test.cc
test.cc: In function ‘int main()’:
test.cc:7: error: no match for ‘operator+’ in ‘std::istream_iterator<float, char, std::char_traits<char>, long int>(((std::basic_istream<char, std::char_traits<char> >&)(& std::cin))) …
Run Code Online (Sandbox Code Playgroud) 任何人都可以告诉我为什么编译时我写的下面的代码一直在抱怨istream_iterator is not a member of std
请你告诉我吗?多谢你们
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <fstream>
//#include<sstream>
struct field_reader: std::ctype<char> {
field_reader(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(table_size, std::ctype_base::mask());
rc[';'] = std::ctype_base::space;
return &rc[0];
}
};
struct Stud{
double VehicleID;
double FinancialYear;
double VehicleType;
double Manufacturer;
double ConditionScore;
friend std::istream &operator>>(std::istream &is, Stud &s) {
return is >> s.VehicleID >> s.FinancialYear >> s.VehicleType >> s.Manufacturer >> s.ConditionScore;
}
// …
Run Code Online (Sandbox Code Playgroud) 我的程序的目的是打开m行相同长度的文本文件n,逐列读取文件并打印每列.
例如,对于此文本文件
abcd
efgh
jklm
Run Code Online (Sandbox Code Playgroud)
我想打印
a e j
b f k
c g l
d h m
Run Code Online (Sandbox Code Playgroud)
由于一个行长度可以是200 000 000并且列长度可以超过10000,我无法在矩阵中打开内存中的所有文件.
从理论上讲,我希望有一个程序在空间中使用O(m)并在时间上使用O(m*n).
一开始,我不得不考虑这些解决方案:
最后一点,对于某些服务器问题,我只需要使用STL.
我的最后一个想法是创建一个文件的迭代器数组,并在每行的开头初始化这些迭代器.之后,要查看下一列,我只需要增加每个迭代器.这是我的代码
ifstream str2;
str2.open ("Input/test.data", ifstream::in);
int nbline = 3;
int nbcolumn = 4;
int x = 0;
istreambuf_iterator<char> istart (str2);
istreambuf_iterator<char> iend ;
istreambuf_iterator<char>* iarray;
iarray = new istreambuf_iterator<char>[nbline];
while (istart != iend){
if (x % nbcolumn == 0){
iarray[x/nbcolumn] = istart;
}
istart++;
x++;
}
for …
Run Code Online (Sandbox Code Playgroud) 在Scott Meyers的"Effective STL"一书中,有一个将整个文本文件读入std :: string对象的好例子:
std::string sData;
/*** Open the file for reading, binary mode ***/
std::ifstream ifFile (“MyFile.txt”, std::ios_base::binary); // Open for input, binary mode
/*** Read in all the data from the file into one string object ***/
sData.assign (std::istreambuf_iterator <char> (ifFile),
std::istreambuf_iterator <char> ());
Run Code Online (Sandbox Code Playgroud)
请注意,它以8字节字符的形式读取.这非常有效.最近虽然我需要读取包含Unicode文本的文件(即每个字符两个字节).但是,当我尝试(天真地)更改它以将数据从Unicode文本文件读取到std :: wstring对象时,如下所示:
std::wstring wsData;
/*** Open the file for reading, binary mode ***/
std::wifstream ifFile (“MyFile.txt”, std::ios_base::binary); // Open for input, binary mode
/*** Read in all the data from the file …
Run Code Online (Sandbox Code Playgroud) 我有这样的代码
std::ifstream file(filename, std::ios_base::in);
if(file.good())
{
file.imbue(std::locale(std::locale(), new delimeter_tokens()));
for(auto& entry : std::istream_iterator<std::string>(file))
{
std::cout << entry << std::endl;
}
}
file.close();
Run Code Online (Sandbox Code Playgroud)
其中std::istream_iterator<std::string>
的 begin()
和end()
定义如下
template<class T>
std::istream_iterator<T> begin(std::istream_iterator<T>& stream)
{
return stream;
}
template<class T>
std::istream_iterator<T> end(std::istream_iterator<T>& stream)
{
return std::istream_iterator<T>();
}
Run Code Online (Sandbox Code Playgroud)
这也是马克·尼尔森在Dobb博士这里所写的内容.唉,代码无法在我的Visual Studio 2012上使用错误消息进行编译
错误C3312:找不到类型'std :: istream_iterator <_Ty>'的可调用'begin'函数
和
错误C3312:找不到类型'std :: istream_iterator <_Ty>'的可调用'end'函数
问题:有没有我没有注意到的东西,编译器中的错误(不太可能,但只是以防万一)或......好吧,任何想法?
根据Xeo的建议,这些问题会得到很大的清理.为了提供更多的背景和参考,这与我在Stackoverflow上的另一个问题有关,我想知道如何使基于行的解析比通常的循环更清晰.从互联网上进行了一些编码和检查,我的工作草图如下
std::ifstream file(filename, std::ios_base::in);
if(file.good())
{
file.imbue(std::locale(std::locale(), new delimeter_tokens()));
for(auto& entry …
Run Code Online (Sandbox Code Playgroud) N2976建议添加constexpr
标准库中的某些位置.它指出iostream
s不适用于constexpr
EXCEPT结束迭代器.所以istream_iterator
,istreambuf_iterator
并给予constexpr
默认构造函数,就是这样.例如,您可以在libstdc ++实现中看到constexpr
只在整个文件中出现一次.引发这一变化的LWG是#1129.它说:
istream_iterator
并istreambuf_iterator
应支持文字哨兵价值观.默认构造函数经常用于终止范围istreambuf_iterator
,并且istream_iterator
在迭代值类型时很容易成为文字值 .[其余省略]
这对我来说并没有多大意义.有人能告诉我他们的意思吗?
N3308是另一篇提到但没有解释问题的论文:
某些
istream_iterator<T>
构造函数必须是constexpr
ifT
是文字类型.目的是允许存储一种T
内联类型的现有实现技术继续工作.[libstdc ++这样做,_Tp _M_value
]但是,它实际上排除了这种技术:T
不需要标记默认和复制构造函数constexpr
,如果不是,则istream_iterator<T>
构造函数不能被实例化constexpr
.
上面解释了普通的复制构造函数和析构函数,但不是默认构造函数标记为constexpr的原因.
此外,在在线GCC 5.2.0上进行测试,我复制了libstdc ++的实现.唯一的变化是我删除了constexpr istream_iterator()
.在这两种情况下,组件都是相同的.
如果我想计算从a中检索到的一堆数字的总和std::istream
,我可以执行以下操作:
// std::istream & is = ...
int total = std::accumulate(std::istream_iterator<int>(is),
std::istream_iterator<int>(),
0);
Run Code Online (Sandbox Code Playgroud)
但是,如果我想计算它们的平均值,我需要累积两个不同的结果:
std::accumulate
)std::distance
)有没有办法"合并"这两种算法并在迭代器范围的单次传递中"并排"运行它们?我想做的事情如下:
using std::placeholders;
int total, count;
std::tie(total, count) = merge_somehow(std::istream_iterator<int>(is),
std::istream_iterator<int>(),
std::bind(std::accumulate, _1, _2, 0),
std::distance);
double average = (double)total / count;
Run Code Online (Sandbox Code Playgroud)
这可能吗?
我正在尝试对此进行相反的操作:
std::ostream outs; // properly initialized of course
std::set<int> my_set; // ditto
outs << my_set.size();
std::copy( my_set.begin(), my_set.end(), std::ostream_iterator<int>( outs ) );
Run Code Online (Sandbox Code Playgroud)
它应该是这样的:
std::istream ins;
std::set<int>::size_type size;
ins >> size;
std::copy( std::istream_iterator<int>( ins ), std::istream_iterator<int>( ins ) ???, std::inserter( my_set, my_set.end() ) );
Run Code Online (Sandbox Code Playgroud)
但是我坚持使用'end'迭代器 - 输入交互器不能使用std :: advance,我也不能使用两个具有相同源的流...
有什么优雅的方法如何解决这个问题?当然我可以用于循环,但也许有更好的东西:)
我正在使用Microsoft Visual C++编写,我希望我的程序可以使用标准输入或文件读取istream_iterator
.谷歌搜索互联网并没有表明我认为它必须是多么简单.例如,我可以很容易地编写这个并从标准输入中读取:
#include <iostream>
#include <string>
#include <iterator>
using namespace std;
int main()
{
istream_iterator<string> my_it(cin);
for (; my_it != istream_iterator<string>(); my_it++)
printf("%s\n", (*my_it).c_str());
}
Run Code Online (Sandbox Code Playgroud)
或者我可以写这个并从文件中读取:
#include <iostream>
#include <string>
#include <iterator>
#include <fstream>
using namespace std;
int main(int argc, char** argv)
{
ifstream file(argv[1]);
istream_iterator<string> my_it(file);
for (; my_it != istream_iterator<string>(); my_it++)
printf("%s\n", (*my_it).c_str());
}
Run Code Online (Sandbox Code Playgroud)
但是我如何将这两者结合起来以便简单的(argc == 2)
检查让我用文件流或stdin初始化我的输入流迭代器并继续我的快乐方式?