When should I use std_logic_vector and when should I use other data types?
I suggest to not use std_logic and std_logic_vector unless you try to model tristate signals - which I consider as kind of evil. Instead using std_ulogic and std_ulogic_vector that are not resolved. This has the advantage to detect multiple assignments to unresolved signals during compile. With resolved signals you would detect that mistake late in simulation or synthesis.
Drawback: This suggestion is not very common and using 3rd-party logic with std_logic might require some typecasts.
For arithmetic of std_ulogic_vector use std_numeric. It is then required to cast to either signed or unsigned before the operation and cast the result back to std_ulogic_vector. There is NO such thing as a standard ieee.std_ulogic_unsigned library for unresolved signals.
adder_result <= std_ulogic_vector( unsigned(operant1) + unsigned(operant2) ) ;
increment <= std_ulogic_vector( unsigned(operant) + 1 ) ;
The difference between integer,natural,positive on one side and the unsigned and signed on the other is the representation. Signed and unsigned are subtype of std_logic_vector and more like a bundle (or more precise array) of std_logic wires.
The integer types are rather a mathematical representation of a number. They are usually used more with generics, generate loops and array index. But sometimes synthesis can handle them for arithmetic units too.
Use the data types that are most appropriate for your modeling purposes, including for ports. It is simply not true that synthesis requires that you should only use std_logic or std_logic_vector for ports. Don't believe those that tell you otherwise.
If you need bit vectors with arithmetic support, consider signed/unsigned from ieee.numeric_std. (In VHDL 2008, there is a standard package that adds arithmetic support to std_logic_vector, but I consider that evil.)
There may only be an issue at the very top-level after synthesis, when you want to simulate the synthesized net list. The port types of that net list may not match your top-level RTL interface. However, you can easily fix that when instantiating the gate level, by doing the proper conversions at that moment. That is the proper time for such low-level concerns - they should not influence your RTL modeling style.