简体   繁体   English

如何重载 std::cout << std::endl?

[英]How to overload std::cout << std::endl?

I was wondering if there was anyway I could overload std::cout << std::endl;我想知道是否可以重载std::cout << std::endl; for the endl to not only make a newline but also print a '-' where the newline is supposed to be and then print another newline.对于endl不仅要创建换行符,还要在换行符应该在的位置打印一个'-' ,然后再打印另一个换行符。

Like if I did std::cout << std::endl << '-' << std::endl;就像我做了std::cout << std::endl << '-' << std::endl;

So I assume I must overload << but I'm not sure where to go from there for it to work with endl .所以我假设我必须重载<<但我不确定从那里去哪里让它与endl一起工作。

Inspired by the epic question about indenting std::ostream instances , here is a codecvt class that will add the additional characters.受到关于缩进std::ostream实例史诗问题的启发,这里是一个 codecvt 类,它将添加额外的字符。

The class was adapted from the popular answer by @MartinYork: I copy-pasted the class, adapted it to use a distinct character, and rewrote the for loop into a form I found more natural.该课程改编自@MartinYork 的流行答案:我复制粘贴了该课程,将其改编为使用不同的字符,并将 for 循环重写为我认为更自然的形式。

Here's a working example .这是一个工作示例

#include <iostream>
#include <locale>

class augmented_newline_facet : public std::codecvt<char, char, std::mbstate_t>
{
    const char addition = '-';
public:
    explicit augmented_newline_facet(const char addition, size_t refs = 0) : std::codecvt<char,char,std::mbstate_t>(refs), addition{addition} {}

    using result = std::codecvt_base::result;
    using base = std::codecvt<char,char,std::mbstate_t>;
    using intern_type = base::intern_type;
    using extern_type = base::extern_type;
    using state_type = base::state_type;

    int& state(state_type& s) const {return *reinterpret_cast<int*>(&s);}
  protected:
    virtual result do_out(state_type& addition_needed,
                          const intern_type* rStart, const intern_type* rEnd, const intern_type*&   rNewStart,
                          extern_type* wStart, extern_type* wEnd, extern_type*& wNewStart) const override
    {
        result  res = std::codecvt_base::noconv;

        while ((rStart < rEnd) && (wStart < wEnd))
        {
            // The last character seen was a newline.
            // Thus we need to add the additional character and an extra newline.
            if (state(addition_needed) == 1)
            {
                *wStart++ = addition;
                *wStart++ = '\n';
                state(addition_needed) = 0;
                res = std::codecvt_base::ok;
                continue;
            }
            else
            {
                // Copy the next character.
                *wStart = *rStart;
            }

            // If the character copied was a '\n' mark that state
            if (*rStart == '\n')
            {
                state(addition_needed) = 1;
            }

            ++rStart;
            ++wStart;
        }

        if (rStart != rEnd)
        {
            res = std::codecvt_base::partial;
        }
        rNewStart   = rStart;
        wNewStart   = wStart;

        return res;
    }

    virtual bool do_always_noconv() const throw() override
    {
        return false; 
    }

};

int main(int argc, char* argv[]) {
    std::ios::sync_with_stdio(false);
    std::cout.imbue(std::locale(std::locale::classic(), 
                                new augmented_newline_facet{'-'}));

    for (int i = 0; i < 5; ++i)
    {
        std::cout << "Line " << i << std::endl;
    }
}

How about defining your own function (or function template) that is akin to std::endl :如何定义自己的类似于std::endl的函数(或函数模板):

std::ostream& enddash(std::ostream& os)
{
    // Can use std::endl in place of '\n' if flushing desired.
    os << "\n-\n";  
    return os;
}

Usage example:用法示例:

int main(int argc, char* argv[]) {
    std::cout << "Hello, world." << enddash;
    std::cout << "Hello, world, once again" << enddash;
}

Output:输出:

Hello, world.
-
Hello, world, once again
-

This is not as cool as @NicholasM's answer, but easier if the main really just contains std::cout << std::endl;这不像@NicholasM 的回答那么酷,但如果 main 真的只包含std::cout << std::endl;更容易std::cout << std::endl; :

#include <stdio.h> // We don't want any iostream stuff, so we use the C header.

namespace std
{
    struct dummy{};

    dummy cout;
    dummy endl;

    dummy& operator<<(dummy &d, const dummy& other){
        printf("\n-\n");
        return d;
    }
}

int main()
{
    std::cout << std::endl;
}

I feel a bit dirty just writing this code...写这段代码我觉得有点脏......

Edit: To be exceedingly clear: I do not encourage anyone to use this code in any meaningful way (As @uneven_mark remarked, it contains UB).编辑:要非常清楚:我不鼓励任何人以任何有意义的方式使用此代码(正如@uneven_mark 所说,它包含 UB)。 It seems to me that the problem was posed to OP as some kind of gag or riddle, and hence I think something like this has the potential to be ok as an answer.在我看来,这个问题是作为某种噱头或谜语向 OP 提出的,因此我认为这样的事情有可能作为答案。

You can do it with a macro definition for endl .您可以使用endl的宏定义来实现。

I don't advise using it, but if you must...我不建议使用它,但如果你必须......

#include <iostream>
#include <string>

#define endl string("\n-\n") << std::flush

int main()
{
    std::cout << std::endl;
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM