lainchan / λ

C++ thread

Hopper · 2023-07-11 09:06
I guess this is a new thread about C++ since the last one appears to be full. >>30762 >Correct. While you ''can'' go right down to the hardware if you'd like, using the STL is almost always a much better choice. The 'hardware' point is easily demonstrated thus: ''The STL itself is written entirely in plain C++''. This pretty much shows it's ready for real-world, industrial-scale use (since the STL is really big & layered). While it is true the STL provides many utilities for generic C++ programming, it is also designed in a quite concerning way (which I admit is in some sense related to the language's semantics). One goal of the STL is providing a generic and adaptive code, and C++ allows that through templates. Templates work as traits/models that, when instantiated, make the compilers generate an actual entity (function, variable, class/struct.) in the code. That way, we have a refined control over compile time code generation which is more powerful that what we could do with syntactical macros. It is so nice that we can even specialize templates for certain arguments making it an actual computation model. Now, one drawback with massive template code is that despite being by definition a zero-cost abstraction (templates are instantiated when a definition is required) the compilation process is much more intensive and errors become much more cryptic. So I wouldn't say that the STL nor any libraries in general that massively use template metaprogramming are specifically fit for "industrial-scale use". Speaking of which, the game industry rarely uses it, simply because its idiomatic design is neither focused on performances nor usability. That is one reason why you find some studios using their own home-made solutions without the template mess (sfinae shenanigans, crtp, and loopholes friend injections are pathological) >Another reason is that if you are dealing with a typical, real-world, convoluted set of data structures, trying to optimize all that by hand can be nigh-on impossible to do well. Again, using the STL instead with it's strong reliance on Template Meta-programming can often result in ''faster'' compiled code by modern optimizing compilers, than any reasonably dev-time-constrained code by hand. I seriously disagree. First and foremost, I doubt the heavy use of tmp is motivated by performances, rather I think it is one solution for generic code which are at the same time zero-cost abstractions. Regarding tmp, it is thankfully not anymore the only way to compute code at compile time (which was anyway a bad idea because of template recursive calls limit). C++11 and recent standards have introduced news keywords for compile time evaluation while preserving code readibility and improving compile times.
Ivan Petrov · 2023-07-12 01:14
What Abseil and https://github.com/alandefreitas/small show is that the STL leaked too much internal design in its API, and is now stuck with it. By the way, we use multiplatform C++17 with a Qt/VTK/CMake/conan stack at work, and it is like kicking dead whales down the beach donkey balls. Even if you use the newer features like constexpr if (still missing constexpr for, recursive templates are a joke), concepts, modules, ranges, or the ridiculously verbose optional, there's just too much legacy and ingrained jank.
Ivan Ilyich · 2023-07-12 04:39
I advise everyone to try nix-shell as a C/C++ package manager (check out NixOS too, interesting distro)
DEBUG-CONTENTS · 2023-07-12 06:58
>>36442 Heard the (ubiquitous) configuration language is an horrible Haskell wannabe and the community is basically Reddit. Guix tried to fix that, at least (CL would have been a better idea, though).
Backus · 2023-07-12 07:29
>>36443 With GNU Shepherd you can write your init scripts in Scheme too.
Ivan Ilyich · 2023-07-13 03:50
>>36443 >Heard the (ubiquitous) configuration language is an horrible Haskell wannabe yes it is, but most of the time you're just setting variables so it's fine (unless you want to do some advanced stuff or read source code, then it is like kicking dead whales down the beach) >community is reddit what do you mean exactly? the only interaction I have with the community is in their matrix channel, people there are helpful, I don't go there to chat I just ask some question and leave >Guix tried to fix that, at least true, but there is nothing in guix that matches home-manager (guix home is still lacking) I might try guix some time
Neuromancer · 2023-10-08 18:24
Wrote a guess the number game with mostly the same functionality in both Rust and C++ , neither of which I have any experience in. I know only so much can be judged based on trivial programs, but I wanted to try anyway for fun. Rust: use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { println!("Guess a number"); let secret_num = rand::thread_rng().gen_range(1..100); let mut attempts = 0; loop { attempts += 1; let mut guess = String::new(); io::stdin() .read_line(&mut guess) .expect("failed to read line"); let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, }; println!("you guessed {guess}"); match guess.cmp(&secret_num){ Ordering::Less => println!("too small"), Ordering::Greater => println!("too large"), Ordering::Equal => { println!("you got it right, attempts: {attempts}"); break; } } }} C++ #include <cstdlib> #include <iostream> #include <time.h> int main() { srand(time(0)); std::cout << "guess a number\n"; int attempts {0}; int secret_num = rand() % 100 + 1; int guess; while(true) { ++attempts; if (!(std::cin >> guess)) { std::cin.clear(); std::cin.ignore(); continue; } std::cout << "you guessed " << guess << "\n"; if (guess == secret_num) { std::cout << "you got it right, attempts: " << attempts << "\n"; break; } std::string message = (guess > secret_num) ? "too large\n" : "too small\n"; std::cout << message; } } C++ felt more concise and straightforward, but Rust has nice error handling and built in string manipulation. C++'s compilation time was way faster , but for real projects maybe that difference isn't as substantial. In any case I'll drop Rust for now and keep learning C++.
Undisclosed · 2023-11-28 17:49
I have this funny relationship with C++. My code tends to be very C-like, but I use things from the STL exactly enough that actually using raw C drives me fuarrrking crazy.
car · 2023-11-28 18:50
What's the current best choice for a c++ linter?
Crash Override · 2023-11-29 13:31
>>37766 I think Clang analyzer/scan-build (also: https://github.com/Ericsson/codechecker) is the best but cppcheck is also very good.
Drano · 2023-12-28 01:06
Reading The PBR Book for my new job. It got me thinking about dynamic dispatch options. The renderer in the book has a lot of small objects in their scene system and opted for tagged pointers over virtual functions. When are virtual functions EVER a good option? The double indirection and mandatory 8 bytes of vtable pointer are horrible for cache coherency. >0 Cost Abstractions The biggest lie of C++. There is no such thing. The cost is at compile time and in the time it takes developers to reason about fuarrrked up template errors.
Morpheus · 2023-12-28 09:32
>>37372 >rand() is from C and should be avoided because it always leads to incorrect code like rand() % 100 + 1 which is biased. In this case it's won't be immediately noticeable if RAND_MAX is large (2^31) but it's there, see https://stackoverflow.com/a/49880109. Instead use https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution >>38021 >When are virtual functions EVER a good option? When a user needs to provide their own implementation of various functions to be used by code not written by the user. They're very frequently used in Linux (which is written in C of course, but it's the exact same concept). For example, for filesystems: struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); .... loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t len, unsigned int remap_flags); int (*fadvise)(struct file *, loff_t, loff_t, int); int (*uring_cmd)(struct io_uring_cmd *ioucmd, unsigned int issue_flags); int (*uring_cmd_iopoll)(struct io_uring_cmd *, struct io_comp_batch *, unsigned int poll_flags); } __randomize_layout; Used in the ext2 driver like so: const struct file_operations ext2_file_operations = { .llseek= generic_file_llseek, .read_iter= ext2_file_read_iter, .write_iter= ext2_file_write_iter, .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl= ext2_compat_ioctl, #endif .mmap= ext2_file_mmap, .open= dquot_file_open, .release= ext2_release_file, .fsync= ext2_fsync, .get_unmapped_area = thp_get_unmapped_area, .splice_read= filemap_splice_read, .splice_write= iter_file_splice_write, }; >The renderer in the book has a lot of small objects in their scene system Graphics code tends to be extremely performance sensitive (much more so than filesystems which instead are very often bottlenecked by disk bandwidth and latency) + the primitives you operate on are usually already known well ahead, so it is practical to avoid dynamic dispatch. >The cost is at compile time "0-cost abstraction" obviously refers to the cost at runtime. If compile time would really be an issue then using C++ is a poor choice and using assembly or Lua would be a better option. >and in the time it takes developers to reason about fuarrrked up template errors. It is a drawback due to how flexible C++ templates are, though "concepts"/constraints should help with that.
let · 2023-12-28 09:46
>>37372 (I know this is a C++ thread but I happen to know Rust reasonably well) Some suggestions: - for guess in io::stdin.lines() { ... } is more "idiomatic" - You can write (in conjunction with for loop) let Ok(guess) = guess.expect("failed to read line").trim().parse::<u32>() else { continue }; which is a wee bit shorter. - instead of matching on Ordering, use guards: match guess { x if x < secret_num => println!("too small"), x if x > secret_num => println!("too large"), _ => { println!("you got it right, attempts: {attempts}"); break; } } which is clearer IMO
Zhora · 2023-12-28 10:24
>>38022 I was referring specifically to the virtual keyword in C++. That struct of function pointers isn't necessarily the same thing. Does a pointer to it exist on every file object? I'm not very familiar with the kernel, and without more context I assume it could easily live on the stack. >"0-cost abstraction" obviously refers to the cost at runtime. It's not true at runtime either. Even unique pointers, the poster child "0-cost abstraction", incurs a runtime cost to move around. >It is a drawback due to how flexible C++ templates are, though "concepts"/constraints should help with that. Sure C++ templates are plenty flexible, but they could have a lot less mental overhead. Other languages handle metaprogramming far more gracefully than C++, which still lacks something like a constexpr if that doesn't introduce a new scope, see static if in D.
Shogun · 2023-12-28 11:06
>>38024 >Does a pointer to it exist on every file object? Yes struct inode { umode_t i_mode; unsigned short i_opflags; kuid_t i_uid; kgid_t i_gid; unsigned int i_flags; ... const struct inode_operations *i_op; ... union { const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ void (*free_inode)(struct inode *); }; ... } __randomize_layout; For ext2 it is set here void ext2_set_file_ops(struct inode *inode) { inode->i_op = &ext2_file_inode_operations; inode->i_fop = &ext2_file_operations; if (IS_DAX(inode)) inode->i_mapping->a_ops = &ext2_dax_aops; else inode->i_mapping->a_ops = &ext2_aops; }
byte · 2023-12-28 12:19
>>38025 >__randomize_layout what is this thing and why is it syntactically correct?
Dox · 2023-12-28 12:29
>>38026 It's an (non-standard) extension for GCC that is part of Linux. It shuffles the fields around so the layout becomes unpredictable. In theory this should help protect against exploits (I believe it's security theater since this randomization is only done for each compilation and nobody is going to recompile the kernel for every single deployment).
queue · 2024-01-20 13:37
Would it be possible to 1. Get a fully featured, 100% standards compliant C++ implementation with no extensions or other nonstandard trickery running on bare metal, and 2. Use it to write an OS kernel? I know Assembly is going to have to figure in at some point, but I'm fine with that. I just want to know how far I can go with True C++ in kernel land.
Leto Atreides I · 2024-01-20 15:17
>>38158 >1. Get a fully featured, 100% standards compliant C++ implementation with no extensions or other nonstandard trickery running on bare metal no. The C++ standard library essentially requires an OS. >2. Use it to write an OS kernel? Yes, although you'll have to write the kernel along with the stdlib for the aforementioned reasons.
Undisclosed · 2024-01-21 21:56
I have no fuarrrking clue what modern C++ is supposed to look like.
Neuromancer · 2024-01-23 05:18
>>38158 >>38162 Even with an OS, writing individually a C++ implementation is just too much. The specification is so dense and contains so many edge cases that even popular implementations can't get everything right. No implementations is fully compliant with the specification which is in turn already inconsistent when it comes to the terminology it heavily uses (template instantiation and specialization are not always considered different) or even some scenarios that are considered archaic but are still theoretically allowed (it is for example possible to retrieve states at compile time using friend injections, I know this loophole is used in some boost libs but it really is accidental : most compilers assume that once a template has been instantiated, it doesn't need to be evaluated again while some others may consider to evaluate it again anyway just in case)
Technician · 2024-01-23 11:14
>>38023 I guess rust made pattern matching and functional programming style quite popular in the industry and honnestly I am quite happy about it. I also really like how traits are implemented just like typeclasses: it is much easier to create constraints on generic code while it would require sfinae/concepts in C++.
protected · 2024-01-26 04:58
The number of times I've wanted CLOS' :before/:after/:around and method combinations instead of just "override" made me hate C++'s soykafty OOP. This together with the lack of keyword arguments is what truly annoys me the most in my professional life. Not the limp-wristed type system, the invisible copies all around, the ever-increasing semantic complexity. Not even the soykafty underpowered metaprogramming/reflection (where's my fuarrrking constexpr for? can I do X - read a file? process a hash table? - using exactly the same code as for runtime? better enums with from/to string and inheritance?).
Tyrell Wellick · 2024-01-26 15:43
>>38198 >I've wanted CLOS' :before/:after/:around and method combinations instead of just "override" made me hate C++'s soykafty OOP. Whats the benefit? From what i could find using before/after is same as writing in c++ this: method(){ *new before code* parent::method(); *new after code*}
Boole · 2024-01-29 07:00
>>38199 The benefit is when you work in a large and/or soykafty "professional" codebase, you want to enforce a behaviour from the top (and :around is different from your examples) without having to write tons of boilerplate and chase forgotten cases. I mean, is your question really "what's the point of aspect oriented programming"? Really?
Linda Lee · 2024-02-16 12:20
Is there a good reason people use [] instead of .at() ? They'll say it's better for performance, but from what I've seen, a good compiler will output the same code for both when it knows you don't need a bounds check. Is this one of those cases where people don't actually read the assembly and just assume everyone else knows what they're talking about, or is there genuinely something I'm missing?
typedef · 2024-02-16 13:52
>>38354 At least to me, writing `[]` is slightly more convenient than `.at()` and also clearer at a glance. Performance-wise it's unlikely to have a significant impact (if at all, as you noted). I think `[]` lacking bound checks is just an unfortunate holdover which nowadays is justified with plausible nonsense and no measurements, like far too many other claims.
Frank Garza · 2024-02-17 20:43
Why is int *foo the more common style than int* foo ? The latter just makes so much more sense to me. You're not declaring an integer named *foo; you're creating an integer pointer named foo.
The Fin · 2024-02-17 21:28
>>38366 because C has stupid syntax where in multi variable declarations the * applies to the variable name rather than the type. int* a, b, *c; is the same as int*a; int b; int *c; So in multi variable declarations its misleading to have * next to the typename instead of the variable name.
Kay · 2024-02-17 21:32
>>38367 Very weird. I gotta agree with >>38366 I've always read it as "foo of type pointer to int" guess I'll just follow a standard of using `int* foo` when it's a single variable declaration and `int *foo` when multiple
Special Agent Bob · 2024-02-18 00:54
I'm still shocked that C++ is a real language.
Spooky · 2024-02-18 16:43
>>38371 C++'s initial goal was to be C, Simula, and Ada all in one package, and it never fully escaped that kind of thinking. Offering support for such vastly different levels of programming in vastly different styles all in the same language from the mid-80s means doing some pretty nutty things.
Demeere · 2024-02-18 17:14
>>38366 When you declare a function or object in C or C++, you give a type identifier and a declarator. When declaring a pointer, array or function, the type identifier is the type pointed to, member type or type returned respectively (potentially with cv qualifiers), and all the stars, brackets and parameter lists are part of the declarators. A well-known place where this matters is that when declaring several variables in the same statement, the type identifier is needed only once while each variable needs a declarator, leading to things like this: int *a, b; // a is a pointer to int, b is an int int a[3], b; // a is an array of 3 ints, b is an int int (*a)(void), b; // a is a pointer to a function of type int(void), b is an int Sticking the star to the identifier rather than the type identifier makes it harder to forget it when declaring several variables in the same statement. That being said, the official guideline in C++ is to only declare one variable by statement and stick the star to the type identifier instead. They justify it because the type system in C++ plays a much bigger role than in C, so it makes more sense to use a syntax that emphasizes types more. See: ES.10 and NL.18 https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
John Doe · 2024-02-18 18:25
>>38377 C++ is to C as lung cancer is to lung -somebody on the internet
Delilah · 2024-02-19 12:55
>>38371 Just treat C++ as C with STL data structures.
Dozer · 2024-02-24 15:33
>>38021 do virtual functions actually cause performance issues?
Y.T · 2024-02-24 17:13
>>38423 It's basically the difference between calling a function by its identifier and calling it by a function pointer whose value the compiler can't determine at compile time. It's not a huge cost, but if the function is called often, it could be significant. In modern C++, there are tons of ways to get around it, the most idiomatic one being std::visit. Look for CppCon talks about "value semantics" if you want in-depth discussions about this.
quote · 2024-02-26 07:14
>>38424 isnt the pointer storing the identifier? My mental model was function calls are all just pointers unless defined inline in which case it actually simply injects the function code into the place where its defined. Only exception is if you have a function call with static parameters in which case they can be computed during compile time.
() · 2024-02-26 08:50
>>38432 A function call without a function pointer uses a fixed memory address, in fake asm we would say for example: x86asm call 0x0004 ; Call the function by absolute address Meanwhile to call from a function pointer we have to first dereference the function pointer and then call that address, so we have the price of a dereference in the middle, again in fake asm: x86asm dereference 0x0008 -> fptr ; Go and fetch the address from memory, this is our overhead call fptr ; Call the function from the dereferenced memory The price paid is the overhead of dereferencing the function pointer, putting it into a register and then making a call, rather than simply calling a function by direct address. The models for this are called direct addressing (needing a memory location) and immediate addressing (taking a value). There is extra overhead in fetching the memory location, as instead of having all the data right there for the call so it can be made straight away the CPU has to go and fetch the data at the address before the call.
Miho Iwakura · 2024-02-28 10:40
>>38423 Virtual dispatch by itself has fairly little overhead, especially compared to all the other code being executed. The main (potential) performance penalty comes from missed optimizations as the compiler doesn't know which function(s) will be called and so can't e.g. inline.
The Fin · 2024-02-28 22:38
Biden has spoken https://www.infoworld.com/article/3713203/white-house-urges-developers-to-dump-c-and-c.html >The White House Office of the National Cyber Director (ONCD), in a report released Monday, called on developers to reduce the risk of cyberattacks by using programming languages that don’t have memory safety vulnerabilities. >The new 19-page report from ONCD gave C and C++ as two examples of programming languages with memory safety vulnerabilities, and it named Rust as an example of a programming language it considers safe.
Erik Johansson · 2024-03-02 09:36
>>38448 Rust is a pretty decent language, and it's definitely safer than C++, but it's also way too immature for any kind of government use (as far as I know there's still no real spec beyond "whatever rustc does", which is subject to change). Why not Ada, the language the US government itself fuarrrking commissioned for situations like these back in the 70s? It and C++ have a lot of mutual influence, and they both exist at around the same level.
word · 2024-03-02 10:53
>>38462 I don't know. In the actual report, Ada isn't mentioned even once. https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf I guess Ada is for internal use, and they don't expect private entities to adopt it.
cdr · 2024-03-03 14:47
Yeah there has to actually be programmers that know Ada first before the US government demands it. Why would they waste their time with Ada when there's a larger pool of diehard Rust programmers who are probably willing to work for less money just so they can use Rust? I've never seen Ada mentioned anywhere on the internet except by you and maybe once on Ycombinator whereas the Rewrite it in Rust crowd are frequently on the front pages of programming-centric news sites and win all the polls of "favorite programming language" by Github et al.
Six · 2024-04-16 09:11
What's the idiomatic approach to member functions vs free functions? The difference between the two seems kind of arbitrary to me.
limited · 2024-04-16 12:50
>>38848 Project authors decide the coding style of their C++ projects, there is no such thing as "the idiomatic approach."
Liet Kynes · 2024-04-16 17:06
>>38848 It's pretty much a matter of whether you can talk about the function "from the point of view" of the object it acts on. That and whether or not you need it to be virtual.
Aristóteles Amadópulus · 2024-04-17 11:01
>>38858 Could you please provide some examples? I think I get what you're saying, but I want to be sure.
the Mailman · 2024-04-20 12:01
>>38433 Note that this is a rule of thumb, not an absolute. On ARM (32b), for instance, you can only call within a +-... 32MiB region? Something like that. If you need further than that there are a couple of methods, one of which is the linker injecting a 'trampoline' that implicitly does an indirect call. (You might ask "why would you need >32MiB of code in a single program" - but this also applies to things like "I have an ITCM at one spot and a different RAM at a very different spot in the memory space.") Essentially the linker turning: armasm foo: blx bar ; other stuff here bx lr ; ...skip a few tens of MiBs... bar: ; other stuff here bx lr into armasm foo: blx foo_far_call_to_bar ; other stuff here bx lr foo_far_call_to_bar: ; this is essentially ; ldr pc, [pc+4] ; but for arcane reasons pc has an offset in arm, ; so let's get the assembler to do the math for us ldr pc, [address_of_bar] address_of_bar: .word bar ; ...skip a few tens of MiBs... bar: ; other stuff here bx lr There are various ways of encoding the trampoline (movw/movt pair, pc-relative load, etc, etc.) They all have their advantages and disadvantages. (This is a common issue with RISCs. An arbitrary call requires <mem width in bits> bits to encode... but typically the size of an instruction is <= the bitwidth of memory addresses. You can reclaim a few bits by enforcing function alignment, but you're left with the choice of either spending most of your encoding space on call instructions or restricting how far you can call and using e.g. trampolines. RISCs tend to prefer to spend their encoding space on cheap constant loads instead.) Works great for microcontrollers. Absolutely thrashes the BTB on larger cores.
protected · 2024-08-23 10:40
Spooky · 2024-08-24 11:11
>>38354 There are no performance impacts, but .at is safer, as when you try to access something out of bounds it crashes and throws an exception, while [] gets you UB if somethings gets fuarrrked up. Its actually a very common question. https://abseil.io/tips/224 this article for example, is retarded. In no world you would prefer UB to a long running programming than just a crash/exception.
protected · 2024-08-24 15:18
>>39877 There absolutely can be significant performance impacts. .at has a tendency to result in the compiler being unable to vectorise, in particular. Also there are way too many cases where the compiler is unable to prove that the size of the vector remains the same (a single aliasing write is generally sufficient) and so throws up its hands and inserts bounds checks for every access. Also exceptions are not free, even when you don't actually take said exceptions. I've seen programs where 3/4 of their time is related to the exception table (more bytes loaded from disk, long exception lookups, pushing important info out of cache in favor of a bunch of "defense in depth" exception table entries, etc, etc.) Unfortunately these issues largely arise once you start writing complex code, and as such you get a lot of 9001iq tards who write a simple microbenchmark, proclaim "aktuly", use it everywhere, and then wonder why they get soykaf perf. (Like people who proclaim virtual method calls are free. They can be cheap assuming you're not confusing the compiler, until you run out of the very finite branch prediction resources or you start executing code for the first time, and then suddenly you're running about as well as the winXP upgrade on your old win3.1 box.) It's usually far better to explicitly throw a single bounds check in before the loop. You get clean errors with lowish cost that way. Downside is of course human error.
Motoko Kusanagi · 2024-08-25 07:37
>>39881 >It's usually far better to explicitly throw a single bounds check in before the loop. You get clean errors with lowish cost that way. Downside is of course human error. Alternatively, try to use iterators when practical to do so.
Armitage · 2024-10-17 11:51
>>37765 If feel as though there are two C++ programmers: "I'm tired of using printf" and "Hmm....this code could be twice as object-oriented for no good reason" I'm the former as well lol
dictionary · 2024-10-19 19:01
>>39881 Hmmm, this is important for hardcore tier performant software, where you have learnt this?
Agent Jones · 2024-10-21 11:28
BEHOLD! A fully functional transform wrapper for people who can't use C++20 and its ranges: #include <algorithm> #include <iterator> #include <utility> // https://stackoverflow.com/a/33282279 // Use rebinder<Tcontainer>::rebind<Args...> to change the template parameters of a container // type (e.g. std::vector<double> -> std::vector<int>) template <typename...> struct rebinder; template <template <typename...> class Container, typename... Args> struct rebinder<Container<Args...>> { template <typename... UArgs> using rebind = Container<UArgs...>; }; // Apply fun to each element of cont and return the result in a new container of appropriate // value_type; functional version of std::transform template <typename Tcontainer, typename Tfun> auto map(const Tcontainer& cont, Tfun fun) { using out_value_type = decltype(fun(std::declval<typename Tcontainer::value_type>())); using out_type = typename rebinder<Tcontainer>::template rebind<out_value_type>; out_type ret; // TODO: detect presence of reserve() and use that instead of back_inserter std::transform(std::begin(cont), std::end(cont), std::back_inserter(ret), fun); return ret; } #include <cmath> #include <vector> int main(void) { const std::vector<float> dvec{1.5, 2.5}; const auto ivec = map(dvec, std::lroundf); } PS: I really hate this retarded language, but I have to use it at work.
Meddler · 2024-10-31 21:14
Is there any reason not to use the <cstdint> types? I understand they're more verbose, which can be annoying, but beyond that, std::int_fast32_t seems a lot more portable and a lot more explicit than int .
Zhora · 2024-11-01 00:55
>>40300 Such verbosity jump isn't just "annoying", it actively impedes readability. The way is to use those (and not the _fast or _least versions) when you need to speak with software where it matters (e.g. machine learning tensors), do proper binary serialization or pack stuff in large arrays. For single variables holding the banana count of your function, int/unsigned/size_t will usually solve 99% of your problems. Just don't use int with -1 as sentinel instead of std::optional<unsigned>, that's a soykafty hack.
Mentat · 2024-11-01 12:38
>>40301 If the only issue is readability, I can just typedef them with more succinct names. My concern is mostly with performance portability and portability. If there's no performance impact, I'm going to use the option that's more explicit and portable.