19

I am pretty new to C++17 and am attempting to understand the decltype keyword and how it pairs with auto.

Below is a snippet of code that produces an unexpected result.

#include <typeinfo>
#include <iostream>
#include <algorithm>

using namespace std;

int main() {

  int16_t mid = 4;
  auto low = mid - static_cast<int16_t>(2);
  auto hi = mid + static_cast<int16_t>(2);

  int16_t val;
  cin >> val;

  val = std::clamp(val,low,hi);

  return 0;
}

Surprisingly, the compiler tells me there is a mismatch in clamp and that low and high are int. If I change auto to int16_t all is good in the world and all the types are int16_t as expected.

The question I'm posing is, why does auto cast low and hi to int when all of the types are int16_t? Is this a good use case for decltype?

Even after reading cppreference.com, I don't fully understand how decltype works, so excuse my ignorance.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Max
  • 2,072
  • 5
  • 26
  • 42
  • you can indeed use `decltype(mid) low = mid - ...` or cast the whole expression `auto low = static_cast(mid - ...)` – Nayfe Apr 29 '19 at 14:40
  • Possible duplicate of [Why must a short be converted to an int before arithmetic operations in C and C++?](https://stackoverflow.com/questions/24371868/why-must-a-short-be-converted-to-an-int-before-arithmetic-operations-in-c-and-c) – phuclv Apr 30 '19 at 02:38
  • [Do arithmetic operators have to promote integral arguments to int?](https://stackoverflow.com/q/47336098/995714), [Why are integer types promoted during addition in C?](https://stackoverflow.com/q/29817927/995714)... – phuclv Apr 30 '19 at 02:47

2 Answers2

20

The problem isn't with auto here. When you subtract two int16_t values, the result is an int. We can demonstrate it with this code here:

#include <iostream>
#include <cstdint>
using namespace std;

template<class T>
void print_type(T) {
    std::cout << __PRETTY_FUNCTION__ << std::endl; 
}

int main() {
    int16_t a = 10;
    int16_t b = 20;
    print_type(a);
    print_type(b);
    print_type(a - b); 
    return 0;
}

a and b are both short ints, but when you add or subtract them it produces a regular int. This is to help prevent overflow / and is also for backwards compatibility.

Alecto Irene Perez
  • 10,321
  • 23
  • 46
5

This phenomenon is called the usual arithmetic conversions. It is defined in the C and C++ standards and (roughly said) converts anything smaller than an int to an int. It converts larger types as well. Take some time and read about it, you'll need it quite often.

Roland Illig
  • 40,703
  • 10
  • 88
  • 121