std::map<std::string, int> numbers {
{ "one", 1 }, {"two", 2 }, { "three", 3 }
};
// each time entry is copied from pair<const string, int>!
std::for_each(std::begin(numbers), std::end(numbers),
[](const std::pair<std::string, int>& entry) {
std::cout << entry.first << " = " << entry.second << '\n';
}
);
This has an error, which is harder to commit in c++14 and forward, with a more compact expression: std::for_each(std::begin(numbers), std::end(numbers),
[](const auto& entry) {
std::cout << entry.first << " = " << entry.second << '\n';
}
); typedef std::map<std::string, int> Numbers;
Numbers numbers {
{ "one", 1 }, {"two", 2 }, { "three", 3 }
};
// each time entry is copied from pair<const string, int>!
std::for_each(std::begin(numbers), std::end(numbers),
[](const Numbers::value_type& entry) {
std::cout << entry.first << " = " << entry.second << '\n';
}
);
Or if you're feeling particularly pedantically correct, you can replace const Numbers::value_type& with Numbers::const_reference, but I don't go that far generally.IMHO one of the mistakes of (many, even very experienced) C++ programmers is that they don't realize typedefs are such a powerful tool to be used liberally throughout a code base, and they instead overuse auto and decltype. Typedefs prevent you from repeating yourself, prevent accidents like these, make changing the underlying types a breeze, are self-documenting, and (when needed on occasion) let you use a different type for a variable than the expression used to initialize it, which isn't possible with auto.
I'd definitely prefer writing in OCaml every day if I could, but I can understand why a lot of C++ is the way it is, and having the newer features is an improvement on the day-to-day.
The same could be said of APL, PHP, or Brainfuck. Having to get into the headspace of C++ is one of the language's weaknesses. A true high-level language doesn't force programmers to spend half their time thinking about how the compiler internals deal with lvalues vs. rvalues, move semantics, decision trees for choosing which promotion or operator overload to do, and so on ad nauseam. Compilers are supposed to be assistants, there to relieve programmers of some drudgery, but C++ compilers are always like malicious assistants determined to do the opposite whenever they can. It's often more work getting them to do the right thing than to do it yourself in Plain Old C - which is what I'd rather do if I can't use a better high-level language than C++.
JavaScript does this with the endless development tooling options and configurations.
So it’s not limited to the language but I see adding to the mental load of a programmer - while they are programming - to be a far worse issue. Context switching is hard enough without all that.
I feel like Rust (eg: `cargo build`) or Ruby gems provide a very different, standardized experienced compared to the two.
Based on what you mention though, I'd encourage you to use "Plain Old C" (ANSI, C99, or C11?) if it helps you be more productive. I can imagine with more and more languages fitting the that semi low-level space (eg: Rust and Zig) coming on the scene, there's a lot more opportunity to find the right tool than ever before.
I doubt you'll find many people who are would say "C++ is intended to be a true high-level language".
If that is actually how C++ is being sold that is indeed wrong. Same if that's how Rust were hypothetically being sold.
Both make you think really hard about ownership for purposes of faster memory management. They're not "true high-level lanaguages". They are systems languages with zero-cost abstractions where possible.
And a few of the examples are about how template errors will become less complex not more.
So I think C++ should either be close to a full time job where you have to learn all the details or you probably shouldn't do it.