Nope you don't, that's what typedefs are for. They're underrated for sure though. People don't use them nearly as much as they should. They're incredibly valuable for avoiding precisely this problem.
String foo = "bar"; String baz = foo;
The `String`s can be completely avoided in languages with type inference because it's obvious that a string literal is a string.
or auto&&. Did you really intend to make a copy?
I remember my first attempts at programming and being annoyed that I can't add a string and an int; ever since that little bit of housekeeping of using types made sense to me and I can clearly see how it eliminates entire classes of errors.
I find it more painful to read code that has too many type annotations. I also find it painful to read code that has too few, so I'd argue there's a bit of an art to it.
But languages that have type inference but allow type annotations at least allow you to try to hit that balance.
Type inference doesn't make these errors go away.
And about your other point, it's unfair to look at just a simple case of writing "string" or not as the only thing inference provides. Although I'd argue that leaving out types where possible helps readability-- it's really the more elaborate cases or intermediate steps during a longer transformation that inference helps with. Not to mention the fact that inference in closures is also really nice.
Generally, I prefer being able to read a line of code and understanding exactly what it does. If I need an IDE and have to repeatedly try to find the definition of something then, in my opinion, that's wasting my time.
C++'s 'auto' is really useful but it's over-used IMO. I think that there's a belief that if you're not using 'auto' everywhere then you're not writing 'modern' C++. Just becuase your code compiles doesn't necessarily mean it's correct.
The fact C++ doesn't have Numeric but instead has int and long and unsigned and long long and float and double all off on their own is another problem: The compiler knows enough about them to have complex promotion rules but doesn't know enough to allow me to refer to all of them under one name in my code.
> I can have an array of T, but I can't specify that T is Numeric?
Sure you can. If you have C++20 concepts:
template<class T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template<Numeric T>
T twice(T x)
{ return x + x; }
Or if you're on a C++11 compiler: template<class T>
typename std::enable_if<
std::is_arithmetic<T>::value,
T>::type twice(T x)
{ return x + x; } Numeric auto twice(Numeric auto x)
{ return x + x; }> I can have an array of T, but I can't specify that T is Numeric?
This is what type-traits and 'concepts' are for, right?
> The compiler knows enough about them to have complex promotion rules but doesn't know enough to allow me to refer to all of them under one name in my code.
This is what std::is_integral gives you.