[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)