Now that I've typed that out though it kinda seems that List<Value> would be clearer, if not for the years of getting used to List<T> being the standard.
You shouldn't be talking about the meaning of T from the consumers perspective, but you should be describing it at the level of abstraction that your generic code is operating at.
I suppose clearer is a question of semantics, but to me there's not any more information conveyed by writing List<Value> vs List<T> - we already know T is a "Value" (because it has to be, due to List).
The data structure itself should provide the needed context - if the base data structure is so complex that the meaning of its generic parameters isn't obvious, that may be a case where naming them makes sense... but to me it's also a code smell of square-peg-in-round-hole.
So if your code targets beginners, especially ESL people, then the verbosity has value to make that first time as easy as possible. Then it becomes noisy and weights you down.
That's an "easy" case, but in my experience, it happens all the time (though it might be especially true in C++). Should I use that "advanced"/uncommon language feature? Do I use it, but document what it does because I expect most people that will read the code not to know about it? If I'm in a part of the code base where the C embedded engineers contribute frequently, I'm going to err on the side of verbosity/clarity. On a code base with experienced C++ Dev, less so.
> I suppose clearer is a question of semantics, but to me there's not any more information conveyed by writing List<Value> vs List<T> - we already know T is a "Value" (because it has to be, due to List).
Yes, I agree. However, think about functions taking 3 or more generic parameters. There's a much larger need for better information in that context