【问题标题】:c++ Clear stringstream using one-liner m.swap(std::stringstream());?c++ 使用单线清除字符串流 m.swap(std::stringstream());?
【发布时间】:2014-05-17 21:12:07
【问题描述】:

我一直在用下面的代码清除std::stringstream:

m.swap(std::stringstream());

代码可能取自this SO thread。最近我在 Visual Studio 2013 中编译了我的代码,我收到了以下警告:

warning C4239: nonstandard extension used : 'argument' : conversion from 'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>' to 'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>> &'
1>          A non-const reference may only be bound to an lvalue

在使用 /W4 的早期版本的 Visual Studio 中,我没有收到任何警告。我记得我在早期版本中无法可靠地清除字符串流,这就是我最终使用该代码的原因。

那么以这种方式清除字符串流是否可移植,如果不能,您能解释一下为什么不这样做吗?还有一种清除字符串流的便携式方法吗?谢谢

编辑:这是请求的代码。使用/W4 编译它以查看警告。

int _tmain(int argc, _TCHAR* argv[])
{
    std::stringstream m;
    m.swap(std::stringstream());

    return 0;
}

【问题讨论】:

  • 我无法重现它,你能发布一些代码吗?
  • @Manu343726 放松,伙计。
  • 在我的 VS++2013 中编译正常。
  • @Manu343726 因为没有其他编译器具有非标准扩展。哦,等等,他们都这样做。 (不可否认,这个特定的扩展确实很糟糕)
  • 我在 VS2013 中做了一个控制台应用程序,我运行你发布的代码没有优化,我无法重现。它编译良好,没有警告。

标签: c++ visual-studio-2013 stringstream


【解决方案1】:

这是std::stringstream::swap()的签名:

void swap( basic_stringstream& other );

如您所见,swap() 对其参数采用左值引用。正如您的编译器正确告诉您的那样,右值或临时值不能绑定到左值引用。一些编译器支持允许您执行此操作的非标准扩展,但我建议您保持在标准范围内,这样会更安全。

但是,虽然您可能无法将临时值绑定到左值引用,但您可以使用此 std::skipws 技巧将临时值转换为左值:

m.swap(static_cast<std::stringstream&>(stringstream{} >> std::skipws));

甚至

std::stringstream{}.swap(m):

在第一个示例中,函数 operator&gt;&gt;() 返回一个对流的引用,它可以安全地与 swap() 一起使用,因为保存参数的引用在函数结束时被销毁。

【讨论】:

  • 感谢您的回答和想法。
  • @vsoftco 它到底是怎么工作的?您是否收到错误消息?如果有,是什么?
  • 是的,error: non-const lvalue reference to type 'std::__1::basic_stringstream&lt;char, std::__1::char_traits&lt;char&gt;, std::__1::allocator&lt;char&gt; &gt;' cannot bind to a value of unrelated type 'std::__1::basic_istream&lt;char&gt;'
  • 这是代码#include &lt;sstream&gt; #include &lt;algorithm&gt; using namespace std; int main() { stringstream m; m.swap(stringstream{} &gt;&gt; skipws); }
  • 如果您使用移动函数添加引用,它会起作用,正如您之前提到的关于字符串流的问题。
【解决方案2】:

std::swap 函数需要两个 非常量 参数进行交换。这是因为调用函数时两个参数都发生了变化。同样,std::stringstream::swap(...) 函数采用单个 non-const 参数进行交换。

例如:

std::vector<int> vec1, vec2;
std::swap(vec1, vec2);

在上面的示例中,vec1 和 vec2 都被更改了。当你尝试这样做时......

m.swap(std::stringstream());

...您正在尝试将临时 std::stringstream() 的内容分配给 m 的内容,这对于编译器来说看起来像是一个错误,即使您的意图只是清除 @987654330 的内容@。

要删除警告,只需在执行交换之前声明一个临时的std::stringstream。像这样:

std::stringstream temp;
m.swap(temp);

【讨论】:

  • 或者,先制作临时文件。 std::stringstream().swap(m);
  • @BillyONeal - 事实上你也可以这样做!
  • 有一些类似的问题...请参阅有关 lvalue 模板 stackoverflow.com/questions/23714445/… 的 cmets
  • 基本上,您将临时绑定到非常量左值引用,这是不可能的。您必须使用 C++11 中的移动语义创建对临时 template&lt;typename T&gt; T&amp; ref_from_temp(T&amp;&amp; x) {return x;} 的引用,然后将 m.swap(stringstream()); 替换为 m.swap(ref_from_temp(stringstream()));
  • @vsoftco 感谢您的建议。我决定使用比利的单线器,因为即使它与 C++03 不完全兼容,它也适用于 Visual Studio 2010。
【解决方案3】:

标准不允许使用swap。声明是

template <typename CharT, typename Traits, typename Allocator>
void std::basic_stringstream<CharT, Traits, Allocator>::swap(
    basic_stringstream& other);

这意味着两个stringstream 对象都将被修改。但是表达式std::stringstream() 是一个右值(特别是一个临时的),C++ 不允许将非常量左值引用绑定到临时,因为修改一个临时的通常不是真正的意图。

简单的解决方案是:

m = std::stringstream();

但如果您需要支持不支持 C++11 的编译器,则两者都不起作用,因为在 C++03 标准中,stringstream 没有 swap 函数,也没有公共 operator=。在这种情况下,您需要使用:

m.clear();
m.str(std::string());

【讨论】:

  • 你如何解释发布的示例编译的事实?
  • .str() 的问题显然是它并不总是对我有用,我不记得为什么。
  • m.clear() 可能还需要进行完全重置。也许还有其他事情。仅使用 C++03 函数很难做到这一点。
  • 好的,感谢您提供的额外信息,非常感谢。我决定使用std::stringstream().swap(m);,因为即使它不是 C++03,它也可以在 Visual Studio 2010 和 2013 中使用。我真的想要更好的可移植性,但我不想冒引入错误的风险() 和 str(std::string()) 是必需的。
猜你喜欢
  • 1970-01-01
  • 2021-04-07
  • 2013-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多