【问题标题】:How to pass other variables as args along with std::ostream in a function in C++?如何在 C++ 中的函数中将其他变量作为 args 以及 std::ostream 传递?
【发布时间】:2021-07-16 02:30:25
【问题描述】:

我正在研究一个看起来像这样的函数:

inline std::ostream& mvUp(int n,std::ostream& ss){
    char u[8];
    sprintf(u,"\033[%dA",n);
    ss<<u;
    return ss;
}

并像这样使用它:

std::cout&lt;&lt;mvUp(1);

但它显示错误:

std::cout<<mvUp(1);
     |          ^_____too few args in function call
     ^_______________no operator "<<" match these operands

我也试过了:std::cout&lt;&lt;mvUp(1,std::cout); 但还是不行。

std::cout<<mvUp(1);
     ^_______________no operator "<<" match these operands

现在当我尝试制作它的模板时,

template <int n>
inline std::ostream& mvUp(std::ostream& ss){
    char u[8];
    sprintf(u,"\033[%dA",n);
    ss<<u;
    return ss;
}

并使用它:std::cout&lt;&lt;mvUp&lt;1&gt;,这完全可以正常工作,但问题是模板采用 const args。

无法弄清楚我哪里出错了。当我不传递任何参数时,它在模板中是如何工作的?

【问题讨论】:

  • 你为什么要混合&lt;&lt;和函数?为什么不只是mvUp(1,std::cout);std::cout 可以接受 mvUp&lt;1&gt; 是的函数指针,这就是它编译的原因。
  • 我想编写一个函数,将某些内容输出到传入的 ostream 中,然后返回该流。我不确定这是否正确。

标签: c++ c++11 templates ansi ostream


【解决方案1】:

现代 C++ 代码使用std::string 和其他类。这使得实现这种重载变得微不足道。

#include <string>
#include <sstream>

inline std::string mvUp(int n) {
    std::ostringstream o;

    o << "\033[" << n << "A";
    return o.str();
}

然后,一切都会自动运行:

std::cout<<mvUp(1);

您的mvUp 返回std::string,而现有的&lt;&lt; 重载负责其余的工作。

【讨论】:

    【解决方案2】:

    std::ostream&amp; mvUp(std::ostream&amp; ss); std::cout &lt;&lt; mvUp&lt;1&gt; 起作用的事实不是 C++ 函数调用语法的特性。

    std::coutoperator&lt;&lt; 重载以接受像这样的单参数函数,并通过将自身作为第一个参数传递来调用它们。

    给定std::ostream&amp; mvUp(int n,std::ostream&amp; ss);std::cout&lt;&lt;mvUp(1) 不起作用,因为您的函数没有一个参数。并且std::cout &lt;&lt; mvUp(1,std::cout); 不起作用,因为您的函数返回了无法打印的std::ostream&amp;

    通用的解决方案是使用重载的operator&lt;&lt; 创建一个class。但是,正如另一个答案所暗示的那样,您可以在这里创建一个返回 std::string 的函数,并打印它的返回值。

    【讨论】:

    • 在函数返回字符串上使用流是否有任何区别或性能问题?
    • @DarthCucumber 如果有的话,返回字符串应该更慢。测量一下就知道了。
    【解决方案3】:

    您正在尝试创建自定义 ostream 操纵器,类似于 std::setw() 和来自 &lt;iomanip&gt; 库的其他操纵器。但是你所写的并不是实现它的正确方法。您的操纵器需要返回一个包含您要用来操作流的信息的类型,然后您需要重载 operator&lt;&lt; 以流出该类型。这将使您能够访问ostream,然后您可以根据需要对其进行操作。

    试试这样的:

    struct mvUpS
    {
        int n;
    };
    
    mvUpS mvUp(int n) {
        return mvUpS{n};
    }
    
    std::ostream& operator<<(std::ostream& ss, const mvUpS &s) {
        return ss << "\033[" << s.n << "A";
    }
    

    现在std::cout &lt;&lt; mvUp(1); 将按预期工作。

    Demo

    【讨论】:

    • mvUp 看起来很像mvUpS'ctor,为什么不把逻辑放在那里呢? std::cout &lt;&lt; mvUpS(1); 只会构建临时对象,这并没有什么坏处,对吧?
    • @Quimby mvUpS(1) 将不起作用,因为mvUpS 没有定义构造函数。添加一个:struct mvUpS { int n; myUpS(int n) : n(n) {} }; 然后它将起作用。否则请改用myUpS{1}。但无论哪种方式,如果在未来的某个时候,您决定更改mvUpS 的内容,您将不得不相应地替换mvUpS(1)/mvUpS{1}。使用单独的函数,您可以更好地封装该更改,因此您不必每次都替换 mvUp(1)。这就是标准参数化操纵器的实现方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-16
    • 2017-01-13
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多