如果您希望专门使用operator>>,并且在技术上不需要专门使用字符串,您可以简单地创建一个自定义类,当它从istream 读入时具有您想要的行为。它甚至可以(主要)是字符串的包装器,在读取初始空白时具有自定义行为。
class StringAndNewline{
std::string str_;
friend std::istream& operator>>(std::istream& in, StringAndNewline& str);
public:
StringAndNewline() : str_(){}
StringAndNewline(std::string str) : str_(str){}
const std::string& str() const noexcept {return str_;}
std::string release() {return std::move(str_);}
};
读入操作符的字符串自动忽略所有preceding whitespace 到由当前语言环境定义的非空白字符序列。这是您想要改变的行为,事实证明这样做非常简单。
初始空白的处理通常由称为哨兵对象的东西执行,该对象还检查流是否有效并设置流的failbit(如果它位于文件末尾)。虽然它的默认行为是在遇到非空白字符之前使用空格,但这是由其构造函数中的标志控制的,因此我们可以使用它提供的非常好的封装流有效性检查。
operator>> 的字符串重载生成并检查哨兵,然后读取直到遇到空格、流结束或读取失败。我们可以简单地通过自己处理它来确保它的哨兵永远不会遇到空白。
因此,我们自定义类的自定义operator>> 的最终读入结构将如下所示:
- 制作非空白吃哨兵
- 检查哨兵,如果无效则返回失败的流
- 处理空白
- 将数据读入包装字符串
- 返回流
由于我们只关心空格中的 '\n' 字符,这也很简单:只需在流有效时循环(如果它在满足我们的任何一个条件之前用完空间,它将设置 failbit 就像如果两个条件之一是净值,则退出循环:我们得到一个换行符,或者我们得到一个非空白字符。同样,令人愉快的简单:
std::istream& operator>>(std::istream& in, StringAndNewline& str){
std::istream::sentry sentry{in, true}; // make a sentry that doesn't eat whitespace
if(!sentry){return in;} // check the sentry
std::locale
presentLocale{}; // get the present locale
char presentChar;
while(in.get(presentChar)){ // while the stream is valid
if(presentChar == '\n'){ // if we get a newline
str.str_ = "\\n"; // set the string to an escaped newline
break; // exit the loop
}
// if we get a non-whitespace character
else if(!std::isspace(presentChar, presentLocale)){
in.unget(); // replace the character in the stream
in >> str.str_; // take advantage of the existing string operator
break; // done with loop
}
}
return in; // return the istream, whatever state it might be in
}
完成后,我们设置一个 ostream 操作符以便于打印:
std::ostream& operator<<(std::ostream& out, const StringAndNewline& str){
return out << str.str();
}
并测试我们的代码:
int main (){
std::istringstream file(
"hello\n"
"world\n"
"C++ is the best tool"
);
StringAndNewline
wordOrNewline;
while(file >> wordOrNewline){
std::cout << wordOrNewline << '\n';
}
}
打印这个:
hello
\n
world
\n
C++
is
the
best
tool
就像我们想要的一样! Live on Coliru
如果您真的想轻松地将包装类转换为字符串,您甚至可以编写一个字符串运算符,但我将把它留给您。