But even in the feature flag case, it serves a purpose by allowing old code to be removed in 2 stages rather than 1 (divide and conquer).
It means the old code still compiles, just in case it needs to be reinstated in a hurry.
I agree with you, commented out code is not ok, unless it is an example or pseudo code. The rest is trash and has no place in any reasonable codebase. If you want to see what the code was like six months ago, use git.
Line comments, yes, but not for block comments or #if 0 disabled sections -- if your search result comes from the middle of one of those, it does not look like a comment without the context, and can mislead you.
One of the biggest thing that catches me out with commented out code is wondering why it is commented out. Is it desirable, but not working for some reason? Is it undesirable, but not deleted for some reason? Is the new code an experiment? Is the old code an experiment? If it's an experiment, am I sure the previous person reinstated the correct code?
Even if you say it can be reinstated in a hurry, why would it need to be? When I'm reading the code, that's one of the questions I'll be thinking about. If I see commented out code, I'll start walking back in history and seeing why the code was replaced. Then I'll be wondering if there is some work flow that perhaps we need to retain for some reason.
All of this takes time. If you really want the code to be gone, it's better for me if you remove it. Then I don't have to wonder why it is there.