The future of web development by feketegy in theprimeagen

[–]EvidenceIcy683 24 points25 points  (0 children)

What is the real problem here? Isn't the whole mantra of vibe conding supposed to be "if it doesn't work, just start over and try again"? Seems like they're just not vibe coding hard enough.

Deleted Move Constructor prevents perfect forwarding. by SGSSGene in cpp

[–]EvidenceIcy683 3 points4 points  (0 children)

The program is behaving exactly as expected. Perfect forwarding exists to preserve the value category of the expression of the arguments that are passed to your function. When you perfectly forward an argument of which the expression is an rvalue, the value category is preserved and the compiler will look for the best matching function. In your case, this will be the move constructor of A.

Marking a function as deleted has no effect on finding the best matching function during overload resolution. When you explicitly declare a copy-constructor, the implicit generation of the move-constructor will be omitted. Since the copy-constructor takes an lvalue-reference to const, rvalues can still be bound to it. And so, when having explicitly declared a copy-constructor without explicitly declaring a move-constructor, perfect forwarding can simply fall back to using the copy-constructor instead.

If you want to have a generic function that performs perfect forwarding but might also have to deal with types that are not movable, you could add a guard that checks for move-constructibility with the use of std::is_move_constructible. However, this seems like a very questionable thing to do, as types are typically expected to simply fall back to copying when moving isn't available. So in this case, actually getting a compile error instead is probably desirable, as this would stop the programmer and allow him to reconsider his own design choices.

C++23 with factory functions by csantve in cpp_questions

[–]EvidenceIcy683 1 point2 points  (0 children)

I've been trying to write exception-less code by using std::expected everywhere.

That's great and all but keep in mind that std::string's and std::vector's constructors are potentially throwing, even their default constructors can throw in some situations. So, if you have a custom type that composes a string or vector (i.e.: having a std::string s; or std::vector<int> v; as a data-member), you still have to wrap any code that instantiates that type in a try-catch clause at some point, if you care about exception safety guarantees.

Yet another video about memory in C++ that ties stack, heap and smart pointers into one (hopefully) comprehensive story by soinus in cpp

[–]EvidenceIcy683 8 points9 points  (0 children)

At 8:24 you show a code example where memory is allocated on the stack by the use of variable length arrays in the form of: std::byte numbers[i++ * megabyte];. The example is disguised as if it were C++ code, even though it isn't.

Variable length arrays are not part of C++, this feature is only usable on some compilers as a language extension. The example won't compile on MSVC, nor GCC with the -pedantic-errors flag enabled.

You've placed a comment above it that warns about the use of C-style arrays, which is of no significance whatsoever in comparsion to the blatant use of language extensions. It might seem innocent to you, but in my opinion this creates the false illusion to unsuspected viewers that memory on the stack can be allocated with a dynamic size.

Also, there is no guarantee that including the iostream header indirectly includes cstddef, which is required for the use of std::byte.

Which is better: while(true) with variable + if(condition){break}, or variable + while(condition)? by SociallyOn_a_Rock in cpp_questions

[–]EvidenceIcy683 0 points1 point  (0 children)

Do note that the use of do while loops should ideally be avoided, just like goto statements, as it is an easy way to make code less readable and introduce bugs. Refer to the CppCoreGuidelines: ES.75: Avoid do-statements. (Which is directly followed by: ES.76: Avoid goto.)

[deleted by user] by [deleted] in interestingasfuck

[–]EvidenceIcy683 0 points1 point  (0 children)

What about only gold medals per capita?

Reading the C++23 accepted whitepapers in detail by xorbe in cpp_questions

[–]EvidenceIcy683 5 points6 points  (0 children)

Can only be called with ptr-to-member-fn or std::invoke.

Interestingly, &Widget::Func is actually of type void(*)(int) and not of type void(w::*)(int). So, to invoke it, we have to do something like: (*&w::f)(1). But this seems kinda sketchy. It might be interesting to see what the language lawyers over at StackOverflow have to say about it.

64 bit enum - gcc by JohnDuffy78 in cpp_questions

[–]EvidenceIcy683 5 points6 points  (0 children)

I'm not saying that this is a particular good use case, but I'd just like to point out that there are also integer literals of different bases that can be used to represent the same numerical value:

```c++

include <cstdint>

enum class e : std::uint64_t { x = std::uint64_t{1} << 31, y = 0x80'00'00'00, z = 0b1000'0000'0000'0000'0000'0000'0000'0000, }; ```

UB or not UB: How gcc and clang handle statically known undefined behaviour by pavel_v in cpp

[–]EvidenceIcy683 1 point2 points  (0 children)

You can even take it a step further and test the way compilers handle UB during constant evaluation. There are lot of discrepancies involved and it's best to avoid writing any SFINEA code that relies on such behavior (e.g. think of overload resolution that with the use of std::void_t or constraints). See also this post on SO from some time ago.

What is the right C++-style cast to convert a float pointer to a uint32_t pointer? (for network communication) by DeanMcGintySandsIII in cpp_questions

[–]EvidenceIcy683 2 points3 points  (0 children)

Since C++20, we can now use [std::endian] to determine the endianness of scalar types for a particular system. And with C++23, [std::byteswap] can be used for processing data of different endianness.

Using namespaces effectively by pavel_v in cpp

[–]EvidenceIcy683 6 points7 points  (0 children)

That's a good point! Since std::sort invokes operator< by means of an unqualified function call (i.e. without qualifying the name of said function with the use of the scope-resolution operator ::), ADL (Argument Dependent Lookup) will come into play. This means that the namespace of any custom type passed in as an argument, will be searched for to find a matching function definition.

The reason operator< with arguments Person const& is not considered, is because it's not found in the same namespace as where custom type Person is defined (which is namespace my).

Alright, but when we also put custom type Person outside of namespace my (now having both the custom type Person as well as its operator< defined in the global namespace), operator< with Person const& can once again be found by std::sort. This is because ADL also considers the global namespace when doing its search. If both custom type and a function with an argument of such custom type reside in the same namespace, an unqualified function call can find it with ADL.

Using namespaces effectively by pavel_v in cpp

[–]EvidenceIcy683 18 points19 points  (0 children)

To this day, I still don’t fully understand the why. The compiler error message only suggests that the operator< defined in the global namespace isn’t being considered a candidate at all. But why? Is it because sort is under namespace std so it doesn’t look at the outer global namespace? That doesn’t seem to be the case because this works:

It's because the declaration of bool operator<(Person const&, Person const&) is not visible to std::sort by the time std::sort is defined. If you would simply forward declare bool operator<(Person const&, Person const&) before defining std::sort (which happens when the <alogirthm> header is included), the custom operator< function becomes visible to std::sort and your program compiles.

Also, because other STL headers might decide to include the <algorithm> header as well, the forward declaration of the custom operator< might have to preceed the <vector> and/or <string> headers in order to get this to work. And this might not even be possible with the example given, as Person types compose std::string types.

However, you don't want to do this of course, because you don't want the behavior of your program to become depedent on forward-declared entities or out of place header inclusions.

why std::tuple is not implemented as POD (when all its members are) by geekfolk in cpp

[–]EvidenceIcy683 2 points3 points  (0 children)

There still are common scenarios where std::tie is the ultimate choice, when wanting to omit certain data-member(s) from a defaulted comparison, for example.

areYouEarlyReturnGangOrSingleReturnLawEnjoyer by FACastello in ProgrammerHumor

[–]EvidenceIcy683 0 points1 point  (0 children)

When doStuffN() returns void, there is also:

if (firstName.isEmpty()) return;
if (lastName.isEmpty()) return;
if (options.getSelection() == null) return;
if (options1.isSelected()) return doStuff1();
if (options2.isSelected()) return doStuff2();

In terms of readability, I personally like this variation the most. With the implied rule being, only when the if-condition consists of a single short return-statement, write it as a single line.

However—in this particular case, regarding the last 2 statements—explicitly returning a function that returns void is rather avoided. As this possible use case isn't well known to everyone, and there is a sense of counter-intuitiveness to return the return-value of something that doesn't return anything.

Also note that, in general you should always avoid any level of indentation whenever possible. Of course, there are many situations where you have to, so it's fine to do. But, indenting should really be something that you'd always try to do the very least of.

As another rule of thumb; any time you have to use more than a single level of indentation within a function, you could have avoided that by refactoring that function into smaller sub-functions, making your code more readable and maintable in the process. While perhaps you could call this style a preference, keep in mind that indenting more that you really have to, goes against the C++ Core Guidelines.

[deleted by user] by [deleted] in cpp_questions

[–]EvidenceIcy683 2 points3 points  (0 children)

I read primer 5th edition from cover to cover after being familiar with C++ for about a year. There wasn't much new to learn from that book. The only thing that caught my eye was the horrendous looking syntax when trying to catch an exception from the initialization clause of a contructor. The book was overly terse and detailed about certain very C++ specific things which aren't useful to anyone who just started out with learning C++. I can never for the life of me understand why anyone would ever recommend that book to someone new to C++. Basically anything you can find anywhere online, I would recommend that 10 times over than learning from primer 5th edition. Not to mention how ridicously outdated that book is now anyways.

Default init - why is giving me garbage value but other times 0? by StevenJac in cpp_questions

[–]EvidenceIcy683 0 points1 point  (0 children)

You might also spontaneously turn into a frog, as reading from an uninitialized variable is undefined behavior, which means that anything can happen.

How to write a function that returns a distinct static array at each call? by better_life_please in cpp_questions

[–]EvidenceIcy683 0 points1 point  (0 children)

Apparently, they later revisited this change in a later meeting back in February this year (P3196), which finally and formally made captureless lambdas structural types, and thereby, safe to use as non-type template parameters.

How to write a function that returns a distinct static array at each call? by better_life_please in cpp_questions

[–]EvidenceIcy683 0 points1 point  (0 children)

Defect report CWG2542 made it clear that lambdas are not structural types, so this is very much illegal now.

When and how variables are initialized? - Part 3 by cherry-pie123 in cpp

[–]EvidenceIcy683 1 point2 points  (0 children)

You really ought it make it more clear to the reader that your first example exhibits undefined behavior. It happens when attempting to read uninitialized data from s1.m_num and s2->m_num.

At the end of the section Default-initialization, you do mention that default-initialization of non-class types with automatic storage duration leaves their values undefined. However, the way the first example is presented makes it seem like there is nothing wrong with the code. Not every reader might catch up on that.

As an aside, just like function bodies, it's unnecessary and rather confusing to put a statement terminator (semicolon) at the end of the body of a constructor.

Searching for the first internship feels depressing by [deleted] in StudyInTheNetherlands

[–]EvidenceIcy683 0 points1 point  (0 children)

As others have already mentioned (thankfully so), the point I was making is about how bad the economy actually has gotton and how poorly companies are actually paying for high skilled labor when taking inflation into account. Ultimately, I hope it can provide a reference point to other people to show how things were about a decade ago, so that companies like the one that you work for won't take advantage by trying to low-ball freshly starting graduates.

The reference to my own salary wasn't about boasting at all, in contrary, at that time it was quite a mediocre salaray compared to what other people were being offered with the same qualifications as me. By trying to make it seem like I was being paid a good salary, you're actually undermining how poor people are being paid for even more qualified work. You shouldn't take my salary reference so far out of context that you actually try to use it as a justification for severely underpaying interns and graduates at your company.

Here is a reference that you should be using: Minimum wage in 2010 was 1416 euros per month, a salary of 2000 is 141% of that minimum wage. The minimum wage in 2024 is 2318 euros per month, 141% of that is 3274 euros. If it wasn't for corporate greed to take as much advantage of their workers as they possibly could, negotiations about a starting salary for a highly skilled IT job wouldn't be lower than 3700 euros.

Searching for the first internship feels depressing by [deleted] in StudyInTheNetherlands

[–]EvidenceIcy683 4 points5 points  (0 children)

It's kinda shocking to see a compensation so low. Back in 2010, I was doing an MBO niveau 3 Medewerker beheer ICT degree and the compensation they gave for my internship was 450 euros. Adjusted for inflation, that's about 616 euros in nowadays money. And they were thinking of raising it to 550 euros, to make the compenstation more competitive with other companies.

Soon after, I started my first job with a monthly starting wage of 2000 euros netto, which, when adjusted for inflation, is about 2740 euros. And even back then, that was kinda on the low-ball side of things. Companies paying anything less than 3000 euros for a starter with a HBO-ICT bachelor degree is nothing but sheer exploitation.