3

I was wondering if there was anyway I could overload 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.

Like if I did 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.

David G
  • 94,763
  • 41
  • 167
  • 253
Diego Esquivel
  • 182
  • 1
  • 12
  • 6
    From the comments you posted on the answer given below, it sounds like you have a fairly constrained situation in which (1) you have code you can't modify, and (2) you need to change what it outputs. Can you elaborate on the context here? Is there a reason you can't modify the existing code? Is there a reason that you're looking at changing how `std::endl` works? Would solutions that don't involve changing `std::endl` work for you? – templatetypedef Nov 23 '19 at 22:17
  • [This is how you do it.](https://stackoverflow.com/questions/27336335/c-cout-with-prefix) – jrok Nov 23 '19 at 22:39
  • Yeah they reason is Im not allow to delete anything in the main, but the main has this fucntion std::cout << std::endl which Im supposed to make it do something different than what it usually does but I cant do it in the main I must find another way thats why I just could think about overloading – Diego Esquivel Nov 23 '19 at 22:42
  • 1
    @DiegoEsquivel Please edit your question (there is an "edit" link below it) and add all the requirements in detail to the question. You are already getting all kinds of answers incorporating some or none of the requirements. Also add the `main` that you are given to the question, because if there is a solution *at all* it is going to be very specific to the content of that `main`. – walnut Nov 23 '19 at 22:52
  • http://coliru.stacked-crooked.com/a/ed5742a89b79c9e2 but please don't – Sopel Nov 23 '19 at 23:00

4 Answers4

2

Inspired by the epic question about indenting std::ostream instances, here is a codecvt class that will add the additional characters.

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.

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;
    }
}
NicholasM
  • 4,557
  • 1
  • 20
  • 47
  • Yes that is a nice solution, but OP is saying that they are not allowed to modify the `main` function. I suppose you can put the `std::cout.imbue` into a static initialization, but I think even then technically it has to be odr-used through `main` to actually be executed. – walnut Nov 23 '19 at 22:50
  • I agree, it requires some effort to perform the `imbue` outside of `main()`. As you write, it should be possible with some static initialization in any function/code that the OP is writing. – NicholasM Nov 23 '19 at 22:54
  • Why would it have to be odr-used in `main`? – Lightness Races in Orbit Nov 23 '19 at 23:03
  • @LightnessRaceswithMonica I was thinking of https://eel.is/c++draft/basic#start.dynamic-4 and whether the dynamic initialization can be forced to happen before the `std::cout << std::endl;` if that is all there is in `main`. I am not sure what this implies if there never is any non-initialization odr-use. – walnut Nov 23 '19 at 23:17
1

How about defining your own function (or function template) that is akin to 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
-
NicholasM
  • 4,557
  • 1
  • 20
  • 47
0

This is not as cool as @NicholasM's answer, but easier if the main really just contains 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). 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.

n314159
  • 4,990
  • 1
  • 5
  • 20
  • Not that I am in any way surprised, but what exactly? Defining a own `std::cout`? – n314159 Nov 23 '19 at 22:56
  • 2
    Declaring/defining anything in the `std` namespace, aside from template specializations, without special exception for a particular entity, is undefined behavior if any standard library header is included. You are including `` and there is no exception for `dummy`, `cout`, `endl` and `operator<<`. – walnut Nov 23 '19 at 22:57
0

You can do it with a macro definition for 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;
}
Sopel
  • 1,179
  • 1
  • 10
  • 15
  • 1
    Sadly also undefined behavior, because one isn't allowed to `#define` any identifier used in the standard library when at least one standard library header is included. But I like how wrong it would be even if it was allowed. – walnut Nov 23 '19 at 23:06
  • does it actually apply when the define doesn't affect any standard include (so like, it's not defined before the include)? That's kinda unintuitive. – Sopel Nov 23 '19 at 23:09
  • 1
    Yeah, there is no exception for the order of includes: https://eel.is/c++draft/macro.names#1 In practice this is unlikely to cause any problems, but one probably shouldn't write UB code just because it works. (In any case I think we all agree that `#define endl` is a bad idea in the first place, although it is probably the shortest solution to OP's problem that will work in practice.) – walnut Nov 23 '19 at 23:22