Strangely, the codebase became more maintainable afterwards.
Strangely, the codebase became more maintainable afterwards.
In my opinion, C++ "concepts" are the least useful C++20 addition to the language - awful syntax, redundancy everywhere (multiple ways of writing the same thing). And for what? Potentially better error messages?
Another gripe; of all the generic overloaded words available to describe this C++ feature, "concept" must be the least descriptive, least useful. Why pick such a meaningless name that does absolutely nothing to even suggest what the feature does?
They're not the least useful C++20 addition, in fact they're amongst the most useful ones.
In particular the addition of the "requires" expression is the real killer here.
> And for what? Potentially better error messages?
Removing even more enable_if and making template code even easier to read (you could do some of that with if constexpr + static_assert in C++17, but there were gotchas). Oh and it allows you to check for the presence of members in classes, which you couldn't do before.
That's the name that Stepanov used 30 years ago to describe the informal type constraints of templates and has been in use in the community since them. Choosing anything else for the language feature would not make sense.
edit: I guess digit separators came in C++14, I'm always a little fuzzy there since at work, we jumped straight from 11 -> 17.
C++20 brought a feature that C had decades prior: designated initializers, except it's in a slightly crappier form. Also, spaceship operator (three-way comparison).
Looking at cppreference, it looks like C++17 also brought if constexpr, and standardized a bunch of nonstandard compiler extensions like [[fallthrough]]. C++20 continued standardizing more of those extensions, and also brought concepts / constraints, which are a lot easier to use than template metaprogramming.
You're at least somewhat right though -- none of these are paradigm shifts as C++11 was compared to C++03 (especially with the notion of ownership, especially in the context of std::unique_ptr and std::move).
Optional is nice but slightly awkward in a non-garbage collected language.
IMO variant is one of those things that should not exist in standard.
It tries to implement discriminated union in C++ but that feature is lame without true pattern matching. And you can’t implement pattern matching without thorough syntax level support. So in my books it’s in this academic “let’s pretend a while we are using some other language…” category.
It’s _occassionally_ convenient for sure.
I agree, they should have made it a language/syntax feature. However: if you wanna do a sum type, it does do that. I'd rather have that than nothing.
IMO the C++ standard should focus platform-agnostic functionality and leave the nitty gritty platform interaction to standalone libraries that can be patched and/or replaced as needed.
Why is it this way? As best as I can find it's so that destructors always run in reverse order of construction, I guess there could be some edge cases there that matter. It's not the strongest argument, but it's not nothing.
I have seen my share of teardown races that were fixed by reordering data members. There's nothing quite like having a mutex torn down before the object that it's guarding.
Running destructors in reverse order of construction is really the only thing that makes sense in an RAII world. It's the same argument as running the destructors in reverse order of construction when exiting a scope.
That's still not a great reason for designated initializers being restricted in the same way they were in C90, especially given the advantage of hindsight. It makes a ton of sense if you have explicit dependencies between data members created during construction, but I can't see a way that you can create those dependencies with designated initializers.
Well, consider what would happen if you had members whose value depends on other members. For example, one member is a pointer to another. Or perhaps one member uses RAII to hold a lock and another controls a resource.
Deterministic construction and destruction order is a fundamental feature of C++. Calling it clueless is just an indication one does not know C++.
That question presupposes a particular compiler implementation of designated initializers. Indeed, C90 had the fixed-order requirement until C99 decided this was unnecessary and removed it.
> Well, consider what would happen if you had members whose value depends on other members.
Can you specify a designated initializer in that way, though? Either you specify a value, or you don't; I'm not aware of a way to introduce dependencies between members with a designated initializer. Yes, you can add a default initializer to a specific member, but that only kicks in if it's unspecified by the designated initializer.
With a constructor initializer list, sure, you can absolutely introduce dependencies on previously-constructed members. But that's not the case with a designated initializer.
Much better than having yet another syntax for macros.
this comes up surprisingly often.