5 ms·
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
by nuancebydefault 3y ago
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()...
- 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.
- gavinray 3y agoThis is not widely considered a good practice, please don't "using namespace std".
- emmelaich 3y agoI know it's not recommended but I use it for main(). And extensive formatting and/or output should be minimised outside main(), imho.
- i-use-nixos-btw 3y ago(2) is a point I firmly agree with (though not everyone does), but it’s a hard one. Here’s the way I think about it. I don’t think I’m wrong but I’m absolutely open to being told otherwise. C++ is a language. It has a standard library. The library depends on the language, but the language shouldn’t depend on the library. This is because many applications cannot use the standard library, or parts of it. The conceptual issue with fstrings in C++ is that the formatting is done on a library level. An fstring would be a language feature. It wouldn’t be reasonable for syntax sugar to resolve to a library call. So what we’d need is a way of having parameterised strings that the language knows to separate out into parameters in a function call. For instance: f(f”Hello, {planet}”); would resolve to: f(“Hello, {}”, planet); such that replacing f with std::format, std::print (C++23), fmt::format, fmt::print, spdlog::info, spdlog::error, or even scn::scan (?), would do exactly what you want. However, the expression f”Hello, {planet}” would be meaningless on its own, and care would need to be taken to avoid: std::string x = f”Hello, {planet}”; from resolving to: std::string x = “Hello, {}”, planet; Which would be equivalent to std::string x = planet; Thanks to C++‘s ludicrous comma operator.
- iudqnolq 3y agoThere's precedent for that in JavaScript's format strings. It also allows for cute ideas, like passing the template to a function that does SQL.
- nuancebydefault 3y agoI understand what you are saying. I wonder/doubt if the comma would have to be an explicit step as part of the hand over to the std lib. The comma is a separator that the programmer would use, but does the compiler need that? The compiler needs to translate 1 argument to multiple arguments of multiple types, such that stdlib can receive all info. (The original fstring indeed cannot be expanded by the lib itself, since that would give stdlib a special status). So the needed language feature is a one to multi args translation, where at compile time all types are known. That would mean that in the context of an assignment (in stead of a function argument), the f string does not make sense. In that case the compilation can simply fail, no? I guess the handing over the multiple args of different types is a problem. Not all infinite combinations can be solved by templating and I guess even if it could, the header would contain too much logic since the template expansion needs to happen from the header?
- miohtama 3y agoIt does not have enough greater or less signs in the function signature :)
- BenFrantzDale 3y agoFor 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 3y agoTo 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 3y agoWell 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.
- xmonkee 3y ago>but generally C++ programmers prefer to be explicit and include the namespaces. why, though? Collisions in the stdlib? stdlib is too new to not be the default for these names?
- Kamq 3y agoThe using declaration modifies your namespace. From the docs: namespace X { using ::f; // global f is now visible as ::X::f using A::g; // A::g is now visible as ::X::g } void h() { X::f(); // calls ::f X::g(); // calls A::g } Link to docs: https://en.cppreference.com/w/cpp/language/namespace#Using-directives https://en.cppreference.com/w/cpp/language/namespace#Using-d...
- xmonkee 3y agoThanks
- deleted 3y ago[deleted]
- criddell 3y agoMaps 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 3y agoThis is very useful, thanks!
- jcelerier 3y agofor (auto [s, n]: my_map) copies all the data needlessly, better to use for (const auto& [s, n]: my_map)
- heywhatupboys 3y agowhat a language
- lionkor 3y agojust consider const reference to be the default for non-primitive types
- a_e_k 3y agoMy rule of thumb is to use const references when the sizeof the type is larger than the sizeof a pointer or reference.
- repsilat 3y agoMight be worth using values/copies even a bit bigger, so long as it's "simple" data. This[1] short post argues for passing `std::string_view` (~2 pointers) by value, for - Omitting pointer indirections (loads), - Not forcing the pointee to have an address (i.e. gotta be in memory, not just registers), and - Eliminating aliasing questions, potentially leading to better codegen if the function isn't inlined. 1: https://quuxplusone.github.io/blog/2021/11/09/pass-string-view-by-value/ https://quuxplusone.github.io/blog/2021/11/09/pass-string-vi...