[HN Gopher] Formatting text in C++: Old and new ways
       ___________________________________________________________________
        
       Formatting text in C++: Old and new ways
        
       Author : signa11
       Score  : 64 points
       Date   : 2023-09-15 23:07 UTC (23 hours ago)
        
 (HTM) web link (mariusbancila.ro)
 (TXT) w3m dump (mariusbancila.ro)
        
       | bowsamic wrote:
       | The C++ STL is so bad in so many ways, it never ceases to amaze
       | me
        
       | 38 wrote:
       | unsigned char str[]{3,4,5,6,0};         std::stringstream ss;
       | ss << "str=" << str;         std::string text = ss.str();
       | 
       | > The content of text will be "str=".
       | 
       | no, it wont. if you are on an old Windows with code page 437 then
       | sure. but on any sane UTF-8 system, you're just going to get some
       | binary data.
       | 
       | 1. https://wikipedia.org/wiki/Code_page_437
        
         | mrcode007 wrote:
         | Thanks for finding this out as a codepage issue. The
         | implementation of the operator<< will indeed call
         | ostream::widen() to expand character into a locale dependent
         | equivalent.
        
       | lysium wrote:
       | Why do execution times drop so drastically with increasing number
       | of iterations? Shouldn't the caches be filled after one iteration
       | already? There is no JIT in C++, or is it?
        
         | IshKebab wrote:
         | Branch predictor maybe.
        
         | Quekid5 wrote:
         | Your CPU is effectively a virtual machine with stuff like
         | branch prediction, speculative execution w/rollback,
         | pipelining, implicit parallelism, etc. etc.
         | 
         | Of course, it isn't able to do quite as much as a VM running in
         | software (because fixed buffers for everything, etc.), but even
         | so...
        
       | guitarbill wrote:
       | It seems so trite, especially in 2023, but please don't use
       | sprintf. It isn't safe in general. (Even snprintf is tricky.)
        
         | consoomer wrote:
         | YOLO
        
         | 38 wrote:
         | saying "dont use" something isn't really actionable, unless you
         | give a safe alternative.
        
           | jjnoakes wrote:
           | The safe alternatives are in the article.
        
           | thiht wrote:
           | And explain why it's not safe too
        
         | [deleted]
        
         | mkoubaa wrote:
         | There are a lot of use cases where "isn't safe" is absolutely
         | irrelevant
        
       | secondcoming wrote:
       | Does `std::format` still use locales under the hood like
       | `std::stringstream` does?
       | 
       | They dropped locale support for `std::to_chars` so hopefully they
       | can be turned off for `std::format` too
        
       | havermeyer wrote:
       | Something else to consider is compile time versus runtime
       | validation with formatting libraries, e.g. due to passing the
       | wrong number or type of arguments. The Abseil str_format library
       | does compile time validation for both when possible:
       | https://abseil.io/docs/cpp/guides/format
        
         | a_e_k wrote:
         | {fmt} certainly does this too. It works quite nicely with the
         | clangd language server flagging a line as an error until the
         | format string and arguments match.
        
       | jokoon wrote:
       | finally!
       | 
       | I remember using variadic templates to print things in a single
       | function call, like this:                   int i; float f;
       | string s;         print_special(i, f, s);
       | 
       | It would somehow imitate the behavior of python's print()
       | 
       | I never really understood how variadic template worked, maybe one
       | day I will, and to be honest, I'm suspecting it's really not very
       | kind to compile time, it's a lot of type checks done under the
       | hood.
       | 
       | It's a bit problematic that C++ cannot be compiled quickly
       | without a fast CPU, I wonder how this is going to be addressed
       | one day, because it seems that modules aren't a good solution to
       | that, yet.
        
       | nuancebydefault wrote:
       | I find it disappointing that cpp20 still doesn't have a solution
       | that is more convenient than good ol printf (except for memory
       | safety).
       | 
       | Another example would be convenient list comprehension,
       | convenient maps wihout juggling around with tuples, first(),
       | second(), at()...
        
         | criddell wrote:
         | Maps have been improved quite a bit.
         | 
         | For example, if you have a std::map<std::string, int>, you can
         | iterate over it like this:                   for (auto [s, n]:
         | my_map) {             // s = string key, n = int value
         | }
         | 
         | You can test for membership:                   if
         | (my_map.contains("foo")) { /* do something * }
         | 
         | Although I still usually use find because if the key is in the
         | map, I probably want the value.
         | 
         | You can use initialization lists with them too:
         | std::map<std::string, int> my_map = {           { "one", 1 },
         | { "two", 2 },           { "three", 3 }         };
        
           | nuancebydefault wrote:
           | This is very useful, thanks!
        
           | jcelerier wrote:
           | for (auto [s, n]: my_map)
           | 
           | copies all the data needlessly, better to use
           | for (const auto& [s, n]: my_map)
        
             | nuancebydefault wrote:
             | That's why some newer languages have 'const are the
             | default'.
        
               | Tommstein wrote:
               | I'm pretty sure it's the reference that makes the data
               | not be copied.
        
               | nly wrote:
               | Without the const the key would still be const.
        
               | nuancebydefault wrote:
               | Copying the data to a const makes little sense in this
               | case. The extra & choice that has emerged makes things
               | more complicated than needed. The sad faith of this old
               | language.
        
             | heywhatupboys wrote:
             | what a language
        
               | lionkor wrote:
               | just consider const reference to be the default for non-
               | primitive types
        
               | a_e_k wrote:
               | My rule of thumb is to use const references when the
               | sizeof the type is larger than the sizeof a pointer or
               | reference.
        
         | halayli wrote:
         | What's wrong with std::format?
        
           | nuancebydefault wrote:
           | Nothing but
           | 
           | (1) notation wise not very different from the old printf
           | which is looked down upon.
           | 
           | (2) f"{name}'s hobby is {hobby} " would read like a novel and
           | there a lot less comma seperated arguments.
           | 
           | (3) std::format is quite a lot of characters to type for
           | something so ubiquitous.
        
             | f1refly wrote:
             | Typically, you'd just `using namespace std` on top of you
             | file. Afterwards calls to `format` have the exact same
             | length as `printf`.
        
               | nuancebydefault wrote:
               | I don't understand. I genuinely thought that using using
               | namespace std is considered bad practice because of
               | possible arising conflicts. Also you still need to write
               | the word format (though you could alias it to one
               | character, with same namespace conflict possibilities).
               | Am i pedantic?
        
               | Quekid5 wrote:
               | This is questionable advice. In header files 'using
               | namespace' should never be used, in implementation files
               | it opens up some weird edge cases. Instead, do
               | using fmt = std::format
               | 
               | and then use fmt(...) as the function call.
               | 
               | ... at least that the current advice AIUI.
        
         | BenFrantzDale wrote:
         | For list comprehension, we have (C++23):
         | `std::ranges::to<std::vector>(items |
         | std::views::filter(shouldInclude) | std::views::transform(f))`
         | it's not quite `[f(x) for x in items if shouldInclude(x)]` but
         | it's the same idea.
        
           | nuancebydefault wrote:
           | To be honest, if that's the notation, i will not be very
           | eager to jump on cpp23. That said, I admire people who's
           | minds stay open for c++ improvements and make that effort.
        
             | logicchains wrote:
             | Well you could write it as
             | to<vector>(items | filter(shouldInclude) | transform(f))
             | 
             | if you really want to, but generally C++ programmers prefer
             | to be explicit and include the namespaces.
        
           | Tommstein wrote:
           | Sweet baby Jesus I thought that was a joke as I started
           | reading it. Still not entirely sure.
        
       ___________________________________________________________________
       (page generated 2023-09-16 23:00 UTC)