0

In Microsoft Visual Studio 2015, the following code:

void foo(int8_t a);
void foo(int16_t a);
void foo(int16_t a, int16_t b);

void f()
{
    int8_t x /* = some value */;
    foo(-int16_t(x)); // ERROR
}

Gives the following message:

foo

Error: more than one instance of overloaded function "function" matches the argument list:
    function "foo(int8_t a)"
    function "foo(int16_t a)"
    argument types are: (int)

What is going on here? Shouldn't it say "argument types are: (int16_t)"? Does this have something to with promotion? if so how can I turn promotion off?

Isaac
  • 816
  • 5
  • 12
  • Negating the integer converts it to an `int`. What kind of conversion exactly do you want (both type conversion and negation)? – Ulrich Eckhardt Mar 27 '16 at 07:00
  • I wan't it to sign extend 'x' to a 16-bit integer, take the 2's complement of that, and then pass it to foo(int16_t a) And I belive int is 32-bits on my computer, so why in the world is the negation of a 16-bit integer a 32-bit integer? – Isaac Mar 27 '16 at 07:02
  • Negate before you cast. Negating promotes to a 32-bit integer. – Joseph Thomson Mar 27 '16 at 07:03
  • Converting to `int` simply conforms to the C++ standard. – Ulrich Eckhardt Mar 27 '16 at 07:03
  • If you read about [integer promotions](http://en.cppreference.com/w/cpp/language/implicit_cast#Integral_promotion) you will see that it says that "In particular, [arithmetic operators](http://en.cppreference.com/w/cpp/language/operator_arithmetic) do not accept types smaller than `int` as arguments, and integral promotions are automatically applied after lvalue-to-rvalue conversion," Negation is an arithmetic operator, and so the value is promoted to an `int`. – Some programmer dude Mar 27 '16 at 07:06
  • @Joseph thank you that answers my question! unfortunately you put that in a comment so Stack Overflow won't let me accept that as an answer :( Also whose stupid idea was to make everything an int? it's totally confusion, not to mention potentially memory inefficient. – Isaac Mar 27 '16 at 07:09
  • 1
    @Isaac I believe it's something to do with performance, in that machine size integers may be faster to operate on. Nowadays, intuitive behaviour is probably a much bigger concern, but we are stuck with legacy behaviour for backwards compatibility. – Joseph Thomson Mar 27 '16 at 07:19

2 Answers2

1

Negate before you cast. Negating promotes to a machine size integer, hence the ambiguity.

foo(int16_t(-x));
Joseph Thomson
  • 9,888
  • 1
  • 34
  • 38
1

You're forgetting about the integer promotions. All of the arithmetic operators perform integer promotions on the operands which are having arithmetic done to them.

In the expression -a, for any a, the integer promotions are applied to a. The effect of this is that if a is an integer type narrower than int, then the value is promoted to int.

On your system int is 32-bit, so int16_t is narrower, therefore -(int16_t)x means -(int)(int16_t)x.

If you want to do a negation in 16-bit precision: you can't; you have to do it in int precision and then convert the result back to 16-bit.

In this case foo( (int16_t)-x ) is the simplest way, although in general think about what you are negating. Here -x is -(int)x but in this case that is presumably what you do want to do. If we were using unsigned types you'd need to take more care.

M.M
  • 138,810
  • 21
  • 208
  • 365