Thread: Handling std::endl without std::ostream

  1. #1
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229

    Handling std::endl without std::ostream

    I am working on an alternative implementation of input/output streams that have similar semantics to std::istream and std::ostream (for size reasons - on my microcontroller instantiating an std::iostream uses up 140KB, or roughly half of my available flash memory).

    One thing I really want to support is using std::endl for a more seamless experience for users of my library, who will most likely already have experience using std::iostream. I understand that it will be hacky, but is there a standard compliant way of doing that?

    According to cppreference std::endl is defined like this:
    Code:
    template< class CharT, class Traits >
    std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
    So technically I think I can add an overload to my library like this:
    Code:
    MyStream& operator<<(std::function<std::ostream&(std::ostream&)> f) {
       ...
    }
    But then how would I be able to tell that it's endl vs any other io manipulator (which I don't want/need to support)?

    Thanks

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Why not create your own equivalent of the endl manipulator?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Quote Originally Posted by laserlight View Post
    Why not create your own equivalent of the endl manipulator?
    Because many of the users of my libraries will be reasonably new to C++, so I want to make it behave as much like std::iostream as possible, for simple use cases, from the user's perspective.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Well, you can call your manipulator endl if you want.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Quote Originally Posted by laserlight View Post
    Well, you can call your manipulator endl if you want.
    Yeah but then when they try << std::endl, they get a cryptic error message, since most people don't actually know how IO manipulators work under the hood - a function pointer that takes a pointer to ostream as an argument, and the operator overload just calls it on 'this'. I didn't know that until this morning and I've been writing a lot of C++ for years. Most people probably think it's a (non-function) literal of some sort that the stream does something to itself when it sees one, and the error message wouldn't make any sense.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by cyberfish
    Yeah but then when they try << std::endl, they get a cryptic error message, since most people don't actually know how IO manipulators work under the hood - a function pointer that takes a pointer to ostream as an argument, and the operator overload just calls it on 'this'. I didn't know that until this morning and I've been writing a lot of C++ for years. Most people probably think it's a (non-function) literal of some sort that the stream does something to itself when it sees one, and the error message wouldn't make any sense.
    Cynically, I'd say that until we have template concepts (due to be standardised in C++20), cryptic error messages are just the way of a C++ programmer's life

    That said, what you could try is to overload, then check that std::endl is used with either an assert (but not static_assert, so you have to hope for adequate testing), or by throwing an exception otherwise. I'd still be inclined to define a manipulator for your stream type, then overload to prevent the usage of ostream manipulators, otherwise it is confusing as to why one standard manipulator is permitted but not others. I'm afraid that I don't have an example though: the overload may be more tricky than you envisioned because as specified in the standard, std::endl is a function template.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Yeah that would be nice!

    This is a whole 'nother level of hacky, but it worked!

    Code:
    BufferedOutputStream& operator<<(
        std::ostream& (*manipulator)(std::ostream&)) {
      using char_type = std::ostream::char_type;
      using traits_type = std::ostream::traits_type;
      if (manipulator == &std::endl<char_type, traits_type>) {
        EnqueueOutput("\n", 1);
        Flush();
      } else if (manipulator == &std::flush<char_type, traits_type>) {
        Flush();
      }
      return *this;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. endl vs '\n'
    By MutantJohn in forum C++ Programming
    Replies: 3
    Last Post: 09-17-2013, 04:03 PM
  2. endl or \n ?
    By BlackSlash12 in forum C++ Programming
    Replies: 38
    Last Post: 08-26-2007, 05:17 AM
  3. endl or \n ?
    By plain in forum C++ Programming
    Replies: 5
    Last Post: 09-01-2006, 01:50 PM
  4. endl - \n
    By Hugo716 in forum C++ Programming
    Replies: 8
    Last Post: 05-25-2006, 02:33 PM
  5. endl
    By Mick D in forum C++ Programming
    Replies: 7
    Last Post: 10-20-2005, 12:54 AM

Tags for this Thread