You're asking the wrong question.
The right question is "who should be responsible for ensuring that the desired values are within the limitations required by the data type?"
Let's look at your cases:
void function1(int16_t health, int8_t mana)
{
Object object;
object.health = health;
object.mana = mana;
}
void function2(int health, int mana)
{
Object object;
object.health = static_cast<int16_t>(health); // Cutting int
object.mana = static_cast<int8_t>(mana); // Cutting int
}
The interface of function1
has an explicit size requirement on its types. It is therefore the responsibility of everyone who calls that function to verify that the values that they want to store fit within the sizes specified in the interface.
function2
by contrast has an implicit size requirement. It says that it takes int
s. But it doesn't really; if you pass it values outside of the size of the data type, then it invokes implementation-defined behavior.
In some respects, function1
is better. The sizes for the parameters are explicitly stated. But because of C++'s conversion rules, something as obviously broken as this won't cause even a compile error:
function1(0xFFFFFFF, 23);
That is a narrowing conversion, which is allowed. It invokes implementation-defined behavior, which is probably not what you want.
Thus, the real question is... what do you want?
If the user wants to set the health to more than 0x7FFF, what should your code do? Should it silently accept it and invoke implementation-defined behavior? Or should it provoke an error condition, throw an exception or just flat-out terminate?
If you want to do any of the latter, then you must use function2
(or rather, an error-checking version of function2
). By using it, the implicit interface requirement can at least be verified. This makes it possible to track down code that wants to set the value improperly.
health > MAX_OF_INT16
? Is this impossible? Then makehealth
anint16
. Do you want to truncate the value? Then make it explicit. The second code just screams "I don't know what I'm doing".int
, then I assume I can safely pass it an int. Your function would just do a half-assed attempt to cast it to the correct type, and it would most likely return garbage for anything not in the range of an int16 or int8. I don't see any upside for your second code.