c++ - 插入流的右值引用是否合理有效?

标签 c++ c++11

我做了一个自定义的流类型,叫它error_stream,它派生自std::ostringstream。我还为名为 throw_cpp_class 的流创建了一个自定义操纵器(throw_cppthrow_cpp_class 的一个实例)。我的目标是使用以下语法:

error_stream s;
s << "some error " << message() << throw_cpp; // throw_cpp throws an exception containing contents of the stream.

我发现,通过定义一个插入运算符,该运算符将对流的右值引用作为第一个操作数,我现在可以这样做:

error_stream() << "some error " << message() << throw_cpp;

插入运算符如下所示:

error_stream& operator<<(error_stream&& s, const throw_cpp_class&)
{
    throw s.str();
    return s;
}

这是怎么回事?为什么我可以在需要 error_stream& 的地方返回 error_stream&& 类型的值? (这会调用移动构造函数吗?)。这是非常低效的吗? (并不是我真的很在意,因为异常(exception)情况应该很少见)。

最佳答案

使用这段代码:

error_stream& operator<<(error_stream&& s, const throw_cpp_class&)
{
    throw s.str();
    return s;
}

您可以将 error_stream&& s 作为 error_stream& 返回,因为 s 是一个左值,它不是一个右值。

“什么?”你问? “但是我看到 && 就在那里!”。 C++ 的这一部分很棘手。当您看到 type&& s(并且 type 不是模板)时,这意味着该变量是右值引用,它是从右值“构建”的引用.但它有一个名字:s。任何有名字的东西都是左值。这就是您有时必须调用 std::move原因,因为您必须让编译器知道您希望它再次将该变量视为右值。

Does this invoke the move constructor?).

不,它只是返回对左值 s 的引用。

Is this horribly inefficient? (Not that I really care, given that the exception should be rare).

不,因为没有复制,甚至没有移动发生。


与您的实际问题无关,流的大多数重载是:

ostream& operator<<(ostream&& s, const T&)

那么这意味着除非 throw_cpp流式传输的第一件事,否则不会调用您的重载,因为之前流式传输的内容将返回 ostream&,而不是 error_stream&&。 (请注意,它们应该是模板,但很多不是,这与重点无关)您必须将其转换回 error_stream

此外,这不是操纵器的工作方式。操纵符是函数,当您将这些函数流式传输到流中时,流会调用该函数并将自身 作为参数传递,因此您需要更像这样的东西:

template <class exception, class charT, class traits>
std::basic_ostream<charT,traits>& throw_cpp(std::basic_ostream<charT,traits>& os)
{
    error_stream& self = dynamic_cast<error_stream&>(os); //maybe throws std::bad_cast
    throw exception(self.str());
    return os; //redundant, but the compiler might not know that.
}

Here it is at work (with stringstream)

关于c++ - 插入流的右值引用是否合理有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17287618/

相关文章:

C++11模板解析错误,使用模板别名进行类型推导

c++11 - 组合模板类型的继承

c++ - 数独求解矩阵,while语句给出无限循环

c++ - 是否有免费软件实用程序可以监视 C++ 应用程序的内存泄漏?

c++ - QtWebkit QWebView setUrl内存泄漏

c++ - 使用 BOOST_ASIO_DISABLE_IOCP 有什么缺点?

c++ - C++0x 中的闭包和嵌套 lambda

c++ - std::transform 将一个结构数组复制到另一个

c++ - 基类中 vector 的干净实例化

c++ - 编译一个 MSVC++2010 项目使其可以在 Ubuntu 上运行