7 ms·
Formatting text in C++: Old and new ways
- bowsamic 3y agoThe C++ STL is so bad in so many ways, it never ceases to amaze me
- secondcoming 3y agoDoes `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
- jokoon 3y agofinally! 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.
- ruph123 3y agoWill C++ ever get the possibility to just print the contents of an object like Rust does (with the automatic debug trait)? I am tired of writing my own print functions for random objects when debugging because the API developers did not bother to override the <<operator. One of those things that are hard to accept when coming back from Rust.
- i-use-nixos-btw 3y agoNot until we get reflection. And reflection efforts seem to be at an impasse, so I don’t imagine we will see it for a few years at least. I will add, though, that I’ve found copilot to be very handy when it comes to generating formatting. Last week I used it while writing fmt::formatter specialisations for a library with 50 structs, some having over 20 members. Writing all of them took about 10 minutes. I dare say the same would hold for operator<< overloads.
- ComputerGuru 3y agoRust does not use reflection for this. Reflection support in rust isn’t actually much better than in C++.
- i-use-nixos-btw 3y agoI’m not a rust dev, but looking into how the Debug trait works, it’s basically what we’d need compile time reflection to get in C++. It generates code that uses the class name and class members. In C++ we have no way of doing that (without hacky macro stuff).
- vvanders 3y agoThe fact that Rust also has a pretty-print("{:#}")[1] a single character away is also really convenient. When you're working with JSON or debug printing types it's nice to be able to format that without reaching for external tools. [1] https://doc.rust-lang.org/std/fmt/ https://doc.rust-lang.org/std/fmt/
- deleted 3y ago[deleted]
- shilangyu 3y ago> I am tired of writing my own print functions for random objects when debugging because the API developers did not bother to override the <<operator. Won't you face the same problem in Rust? If the library developer did not derive the Debug trait, you're out of luck.
- deleted 3y ago[deleted]
- alexvitkov 3y agoTIL C++ now has a third builtin way to format strings. Can't wait to not use it.
- deleted 3y ago[deleted]
- 38 3y agounsigned 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 https://wikipedia.org/wiki/Code_page_437
- mrcode007 3y agoThanks 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.
- guitarbill 3y agoIt seems so trite, especially in 2023, but please don't use sprintf. It isn't safe in general. (Even snprintf is tricky.)
- mkoubaa 3y agoThere are a lot of use cases where "isn't safe" is absolutely irrelevant
- i-use-nixos-btw 3y agoOTOH, in many of the cases where “isn’t safe” IS relevant, the developer believes it isn’t.
- kevin_thibedeau 3y agoBuffer overflows are never irrelevant. You might get away with it until the day it blows up or someone manages to exploit it. Or you could code it correctly the first time.
- fsloth 3y ago"It isn't safe in general" Disagree. Use whatever is the most simple and boring option for the problem's solution. Also, the standard library has so much stuff that will give you pain in runtime, that avoiding sprintf really is not relevant. I don't know what "Safe" means in general in the scope of C++. If there is a memory corruption, my program will crash. Then I will compile it with C++ debug runtime, which will pinpoint the exact location that caused the memory leak. Then I fix the leak. Not using sprintf will not result in code that would not have memory leaks. C++ in total is unsafe. You need to write code and have production system that foremost takes this into account. You can't make C++ safe by following dogma of not using functions with possible side-effects. There is a very hight chance your fall-back algorithms themselves will leak memroy anyway. The only way to write 'as non-leaky' C++ as possible is to make the code as simple, and easy to reason about as possible, and to have tooling to assist in program validation. This requirement is much more important than avoiding some parts of standard library. Use static checkers, use Microsoft's debug C runtime, use address sanitizers, etc. If you know some parts of you standard library are broken then ofc avoid them. But what can be considered "broken" really depends what one is trying to achiece, and which platforms one is targeting.
- havermeyer 3y agoSomething 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 https://abseil.io/docs/cpp/guides/format
- a_e_k 3y ago{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.
- nuancebydefault 3y agoI 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()...
- halayli 3y agoWhat's wrong with std::format?
- nuancebydefault 3y agoNothing 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 3y agoTypically, you'd just `using namespace std` on top of you file. Afterwards calls to `format` have the exact same length as `printf`.
- nuancebydefault 3y agoI 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 3y agoThis 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.
- lysium 3y agoWhy 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 3y agoBranch predictor maybe.
- mike_hock 3y agoThat was my guess. Training the branch predictor on all those virtual calls.
- Quekid5 3y agoYour 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...
- deleted 3y ago[deleted]
- deaddodo 3y ago> There is no JIT in C++, or is it? This question doesn't make sense for the context*. C++ is Ahead of Time, by design; there is nothing to "just in time" compile. JIT (as a concept) only makes sense if you are, in some way, abstracting your code from native machine code (usually via some sort of VM, like Python or Java's), which the "system" languages (C, Rust, Zig, C++, etc) do not. What I think you are trying to reference are "runtime optimizations"; in which case, the answer is probably no. Base and STD C++ are pretty conservative about what they put into the runtime. Extended runtimes like Windows' and glibc might do some conditional optimizations, however. * Yes, some contrarian is going to point out a project like Cling or C++/CLI. This is why I'm being very clear about "context".