【问题标题】:Passing temporary istringstream object to istream_iterator<string>将临时 istringstream 对象传递给 istream_iterator<string>
【发布时间】:2014-07-06 00:54:37
【问题描述】:

我对以下用于标记字符串的代码有疑问(用空格分隔标记)。

#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    string s="And I feel fine ...";
    istringstream ss(s);
    vector<string> tokens{istream_iterator<string>(ss),{}};
    for(auto& elem: tokens)
        cout << elem << endl;
}

这工作得很好。另一方面,如果我尝试将临时 istringstream 对象传递给 istream_iteratormain 内的第 3 行),如

vector<string> tokens{istream_iterator<string>(istringstream(s)),{}};

我收到一个编译时错误 error: no matching conversion for functional-style cast from 'istringstream' (aka 'basic_istringstream&lt;char&gt;') to 'istream_iterator&lt;string&gt;'

我相信这是因为我无法将临时右值绑定到非常量左值引用,而istream_iterator 的构造函数将引用作为参数。有没有办法从临时构建一个istream_iterator&lt;string&gt;?我也不能在临时对象上使用std::ref...

谢谢!

【问题讨论】:

    标签: c++ iterator istringstream


    【解决方案1】:

    使用std::skipw 技巧:

    std::vector<std::string> tokens{
        std::istream_iterator<std::string>(std::istringstream(s) >> std::skipws), {}
    };
    

    这是因为提取器返回一个对流的左值引用,并且设置std::skipw 不会有任何效果,因为它默认在所有流上启用。要在一般情况下使用它,您可能希望有一个接受通用引用的函数,然后返回对该对象的引用:

    template<typename T>
    T& lvalue(T&& x)
    {
        return x;
    }
    
    // ...
    std::istream_iterator<std::string>(lvalue(std::istringstream(s)));
    

    确保没有在完整表达式之后使用引用,否则您将有一个悬空引用,因为临时引用已经被破坏。

    【讨论】:

    • 不错!关于 C++ 还有很多东西要学习...出于某种原因,我认为 std::ref 与您的 lvalue 完全一样,但看起来 std::ref 的移动构造函数已被删除,并且它仅将引用作为参数,所以你不能将温度传递给它。 move ctor被删除我觉得很奇怪,你知道原因吗?
    • @vsoftco std::ref 使用引用语义,而不是移动语义。它的唯一目的是将引用包装在对象周围,而不是拥有该对象。此外,std::ref 不适合与临时人员一起使用,因为正如我所说的那样存在明显的悬空引用问题。
    • @0x499602D2 好的,从安全的角度来看,这是有道理的......不过std::skipw 的技巧真的很巧妙......谢谢!
    猜你喜欢
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 2021-11-07
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多