【问题标题】:C++ - Send data in one ostream to another ostreamC ++ - 将一个ostream中的数据发送到另一个ostream
【发布时间】:2013-12-31 00:57:29
【问题描述】:

我不明白这个 ostream 函数声明是什么意思:

ostream& operator<< (ostream& (*pf)(ostream&));

(特别是(*pf)(ostream&amp;) 部分)。我想做类似的事情:

void print(ostream& os){
    cout << os;
}

但我得到了错误:

 Invalid operands to binary expression ('ostream' . . . and 'ostream')

【问题讨论】:

  • 那是给机械手的。
  • 扩展 chris 的评论,声明一个函数 std::ostream&amp; foo(std::ostream&amp; os) { return os &lt;&lt; "foo"; } 然后在你的主代码中尝试 std::cout &lt;&lt; foo &lt;&lt; std::endl; 然后在调试器中单步执行。你很快就会看到它是如何工作的。
  • @IInspectable:Firefox 在此页面上除了您的评论之外的任何地方都找不到 const 一词。那么你所指的“你”是谁,你所指的const在哪里?
  • 您的打印函数签名应该是:ostream&amp; print(ostream&amp; os);,如果您想将其传递给该操作员。操作符签名看起来像是一个函数指针指向我。

标签: c++ iostream


【解决方案1】:

我不明白这个 ostream 函数声明是什么意思:

ostream& operator<< (ostream& (*pf)(ostream&));

你见过std::endlstd::flushstd::hexstd::decstd::setw...等函数吗?它们都可以使用“ostream& (*pf)(ostream&) 参数匹配,并且该运算符是允许使用它们的运算符。如果我们看一下 Visual C++ 的实现...

 _Myt& operator<<(_Myt& (__cdecl *_Pfn)(_Myt&))
 {
      return ((*_Pfn)(*this));
 }

...您可以查看是否只是调用该函数,并将其用作参数的流传递。这些函数应返回对同一流参数的引用,以便可以链接进一步的&lt;&lt; 操作,或者可以将流隐式转换为bool 作为流状态的测试。

有关 io 操纵器的更多信息,请参阅 http://en.cppreference.com/w/cpp/io/manip

您需要帮助:

void print(ostream& os){
    cout << os;
}

这里的问题是您将 ostream 参数发送到另一个流 - cout - 它不知道您希望它做什么。

要将os 的当前内容发送到cout,请尝试:

void print(ostream& os){
    cout << os.rdbuf();
}

或者如果你想将一些实际数据打印到参数所代表的流中:

void print(ostream& os){
    os << "show this!\n";
}

print(std::cout);   // to write "show this!\n" to `std::cout`
print(std::cerr);   // to write "show this!\n" to `std::cerr`

【讨论】:

  • 参考 std::endl 等特别有用。我实际上想将一个 ostream 的内容附加到另一个(这可能表明我真的不知道 ostream 是什么)。
  • @thethuthinnang:这很有意义...通常用于将您在字符串流中准备的数据复制到文件或标准输出/错误...只需使用cout &lt;&lt; os.rdbuf();
【解决方案2】:

声明的含义。

形式论证……

ostream& (*pf)(ostream&)

声明一个名为 pf 的参数,它是一个指针,您可以将带有 ostream&amp; 参数的参数括号应用到该指针,该参数构成一个返回 ostream&amp; 作为结果的调用。

可以简化为……

ostream& pf(ostream&)

您可以更轻松地看到它是一个函数。

缺点是这种形式很少使用,所以不是每个人都知道它会衰减到第一种形式(与 int x[43] 非常相似,因为形式参数类型实际上与 int x[] 相同,因为两者这些形式在函数类型中衰减到仅int* x,因此在函数体中您甚至可以增加x)。


它的用途。

上述形式的函数通常是一个输出流操纵器。这意味着,您可以将其传递给&lt;&lt; 输出运算符。然后发生的只是 &lt;&lt; 调用该函数,并使用流作为参数,如 C++11 §27.7.3.6.3/1 和 2 所指定:

basic_ostream&lt;charT,traits&gt;&amp; operator&lt;&lt; (basic_ostream&lt;charT,traits&gt;&amp; (*pf)(basic_ostream&lt;charT,traits&gt;&amp;))

  1. 效果:无。不表现为格式化输出函数(如 27.7.3.6.1 中所述)。

  2. 返回:pf(*this)

还有一个 &lt;&lt; 的重载,它采用类似的函数,但带有 std::basic_ios&amp; 参数和结果,另一个采用带有 std::ios_base 参数和结果的函数。

std::ios_base 类是 iostreams 类层次结构的基础,在该级别定义的标准操纵器是……:

  • 格式化标志操作符:
    boolalpha, noboolalpha, showbase, noshowbase, showpoint, noshowpoint, showpos, @987654346 @、skipwsnoskipwsuppercasenouppercaseunitbutnounitbuf

  • 调整字段操纵器:
    internalleftright

  • 数字系统基础操纵器:
    dechexoct

  • 浮点数表示操纵器:
    fixedscientifichexfloatdefaultfloat

接受用户参数的操纵器不遵循这种形式,标准提供的操纵器位于名为 &lt;iomanip&gt; 的单独标头中。

示例:用户定义的操纵器。

代码:

#include <iostream>
#include <string>
// With Visual C++, if necessary define __func__ as __FUNCTION__.
using namespace std;

class Logger
{
private:
    string  funcname_;
    static int call_level;

    auto
    static indent( ostream& stream )
        -> ostream&
    { return (stream << string( 4*call_level, ' ' )); }

public:
    Logger( string const& funcname )
        : funcname_( funcname )
    {
        clog << indent << "-> " << funcname_ << endl;
        ++call_level;
    }

    ~Logger()
    {
        --call_level;
        clog << indent << "<- " << funcname_ << endl;
    }
};

int Logger::call_level = 0;

#define WITH_LOGGING Logger logging( __func__ )

void c() { WITH_LOGGING; }
void b() { WITH_LOGGING; c(); }
void a() { WITH_LOGGING; b(); }

auto main() -> int { a(); }

输出,显示调用和返回,很好的缩进:

-> 一个 -> b -> c

【讨论】:

  • @TonyD:是的,但是您建议如何检测差异? :-)
  • @Tony:“左值到右值转换”不适用于函数参数类型调整,因此无关紧要。并且对此类转换数量的限制是无关紧要的。很抱歉,我没有检查(在仔细阅读的意义上)您的原始报价,但这当然也无关紧要,只是它似乎是正确的。标准的相关部分是第 8.3.5/5 节,“确定每个参数的类型后,将任何类型为“T 数组”或“函数返回 T”的参数调整为“指向 T”或“指针函数返回 T,“分别”。 AFAIK 差异是无法检测到的。
  • @TonyD:对不起,不,关于“给定一个实际的 int[43] 参数,您可以匹配模板 void f(int (&x)[N]) - 这是一个非常有用的捕获数组维度的方法。”。这不是图片中形式参数类型衰减的示例。
  • @TonyD:原来的上下文是正式的参数类型,所以这就是它的全部内容。你是对的,可以选择错误的解释(即描述标准委员会如何选择指定效果的细节)。这意味着这种解释是错误的。 ;-)
  • 嗯,我会修正一下措辞,以免误解。但是给我一些时间。这里是深夜。
【解决方案3】:

声明的参数部分:

ostream& operator<< (ostream& (*pf)(ostream&));

是一个函数指针语法。

表达式:

ostream& (*pf)(ostream&)

声明一个指向函数 pf 的指针,该函数接受 ostream&amp; 参数并返回对 ostream 的引用。

如果我声明一个函数:

ostream& my_function(ostream& output);

然后我可以将一个指向函数的指针作为参数传递:

operator<< (my_function);

阅读函数指针语法。搜索网络和stackoverflow。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-18
    相关资源
    最近更新 更多