> I'm not sure that vector should work
Well, I think it "should" work in the sense that I shouldn't have to type "vector" just to get a vector of mutable ints. It's just too much typing for zero benefit. How exactly you make that work is a separate question; you can do it at both the the language and library level. A compromise might be to make 'mutable' be a storage class (like 'register', or like how it already is for class members) rather than a type qualifier. Note that even making it a storage class has a downside: 'return v;' will now copy-construct its output instead of moving it. You'd have to mess with the const rules to get around that. It might be possible but I'd need to think through the implications and actually play around with it for a while before I could suggest that it would actually work well.
> lambda captures [...] Is there a compromise here?
I don't know honestly. One idea could be to see if some dataflow analysis could tell you if the lambda might leak from the scope it's declared in, and you could warn on that. I think there are already tools (like clang-tidy, cppcheck, etc.) that give you warnings of this sort; I'm not sure if they fully handle this case though, you'll have to check and see if those handle the cases you want. It almost certainly won't be something you could whip up in a few hours, in case that's what you were hoping for.
> I'm not sure that goto is required when one could use do { ... } while(false); with break statements for cases where goto would've been used (not ideal, but again this is an iterative approach).
That's in no way a substitute for a goto. Sometimes you really do need the ability to jump in, not just jump out. Imagine a state machine/coroutine/etc.—it's not impossible to write them without goto, but sometimes you'd have to go through contortions and write unnatural/unmaintainable logic to write them without goto. Yes C++20 has coroutine support now but it's mediocre at best and isn't suitable for every use case.
> C style casts to void are useful for some memory operations but I'm not sure there's a case where they're required.
Edit: (void) isn't required anywhere I know of, but there are lots of places where it's helpful to have, and completely unhelpful not to have. Here's one:
void foo(void *p)
{
#if NDBUG
bar(p);
#else
(void)p; // suppress "unused parameter" warning
#endif
}
Sure you can do static_cast(p) but that's not buying you anything. It's not the end of the world, but it's just wasting your time and making your code more verbose to read. I don't have a problem with more verbose typing when it actually buys you something, but there are cases where it doesn't, and this is one of them.
In fact, a better rule might #5 below. I'm not sure there's a reason to ban the C-style cast entirely; it could be much more useful and safer than it is now.
Meta-rule of thumb: you need to make sure you're familiar with the vast array of use cases and scenarios people encounter in real-world C++ before you can come up with rules for other C++ devs to follow. The committee itself has a hard enough time doing this for a good reason—because it's hard! If you are going to propose that some feature is unnecessary, it should be a conclusion you draw after you've already used that feature in its "most useful" context (and found a good alternative)—not before that. Most features have some very compelling use cases, so if you haven't found a compelling use case for a feature ("compelling" assuming you disregard any downsides it might have in other contexts) then there's a good chance you simply haven't come across it yet, rather than it having been unnecessary to begin with. It's usually enlightening (and honestly kind of fun) to try to figure that out before rushing to get rid of it.
> I'd love to hear some of your rules
Sorry I wrote this comment but forgot to respond to this part. I'd have to sit down and think through a lot of them before I can share them with any confidence honestly. But just going off the top of my head, here might be a few:
(1) Conversion operators (like constructors as you mentioned) should probably be explicit by default too
(2) Shadowing local variables (or parameters) in a surrounding scope should probably require something like [[shadow]] somewhere to make it abundantly obvious it's intentional (and its use cases would be
incredibly rare)
(3) Initializing a variable by passing itself as an argument should be disallowed (so struct MyClass { int x; MyClass() : x(x) { } }; should be illegal, i.e. the equivalent of -Werror=init-self should be mandatory)
(4) value-initialization should probably be the default, but with a way to override it and perform default-initialization when there's actually a reason to (but perhaps -Wuninitialized should still treat the variable as uninitialized regardless)
(5) Perhaps the C-style cast should really be equivalent to a static_cast except in cases where a dynamic_cast/reinterpret_cast/const_cast would also be legal, in which case it should be an error? That would make it safer than static_cast (since it's more restrictive in where it's allowed), rather than more dangerous, and it would require less typing as well.