Неявное преобразование и перегрузка оператора

Итак, я написал что-то вроде этого

#include <iostream>
using namespace std;

void f(int32_t i)
{
    cout << "int32: " << i << endl;
}

void f(int16_t i)
{
    cout << "int16: " << i << endl;
}

void f(int8_t i)
{
    cout << "int8: " << i << endl;
}

void f(uint32_t i)
{
    cout << "uint32: " << i << endl;
}

void f(uint16_t i)
{
    cout << "uint16: " << i << endl;
}


int main() {
    uint8_t i = 0u;
    f(i);
    return 0;
}

И это напечатано

int32: 0

Я немного запутался:

  • Это четко определенное поведение, или это конкретная реализация?

  • Какие правила определяют, какая перегрузка здесь используется и в какой тип преобразуется переменная?

Ответ 1

При сравнении преобразований, необходимых для различных перегруженных функций, "продвижение" считается лучшей последовательностью преобразования, чем стандартное "преобразование". Каждый арифметический тип может повышать до одного другого типа. (Акции также используются при передаче аргумента в переменную функцию стиля C, такую как printf. Оператор unary + может использоваться для форсирования арифметического выражения, например, +n.)

Для целочисленных типов, которые не являются типами символов или bool, повышенный тип:

  • Если int может представлять все значения исходного типа, то int;
  • В противном случае, если unsigned int может представлять все значения исходного типа, тогда unsigned int;
  • В противном случае, сам оригинальный тип (продвижение ничего не делает)

В вашем примере, при сравнении перегруженных функций, "точное совпадение" будет лучшим, но нет функции, принимающей в точности int8_t (или int8_t& или const int8_t&). uint8_t тип uint8_t - int, поскольку он должен поддерживать диапазон, намного больший, чем 0-255. И, очевидно, в вашей системе int32_t является псевдонимом для int, поэтому функция void f(int32_t); требует только повышения по аргументу. Все остальные функции являются жизнеспособными, но требуют целочисленного преобразования аргумента. Так что void f(int32_t); считается лучшей перегрузкой.

Таким образом, технический ответ на этот вопрос заключается в том, что он зависит от реализации, но только из-за связи между типами int и <cstdint>, а не из-за правил разрешения перегрузки.

Ответ 2

Поведение четко определено, но зависит от реализации. С 16-битным int все было бы иначе.

Особые правила в стандарте:

[over.best.ics] для разрешения перегрузки. [conv.prom] для комплексного продвижения.