c++ - Por que o valor int mais negativo causa um erro sobre sobrecargas de função ambíguas?




integer overloading (2)

Estou aprendendo sobre sobrecarga de funções em C ++ e me deparei com isso:

void display(int a)
{
    cout << "int" << endl;
}

void display(unsigned a)
{
    cout << "unsigned" << endl;
}

int main()
{
    int i = -2147483648;
    cout << i << endl; //will display -2147483648
    display(-2147483648);
}

Pelo que eu entendi, qualquer valor dado no intervalo int (no meu caso int é de 4 bytes) vai chamar display(int) e qualquer valor fora desse intervalo será ambíguo (já que o compilador não pode decidir qual função chamar). É válido para o intervalo completo de valores int , exceto seu valor mínimo, ou seja, -2147483648 que a compilação falha com o erro

chamada de display(long int) sobrecarregada display(long int) é ambígua

Mas, tendo o mesmo valor para um int e imprimindo, o valor dá 2147483648 . Estou literalmente confuso com esse comportamento.

Por que esse comportamento é observado apenas quando o número mais negativo é passado? (O comportamento é o mesmo se um short é usado com -32768 - na verdade, em qualquer caso, onde o número negativo e o número positivo têm a mesma representação binária)

Compilador usado: g ++ (GCC) 4.8.5


A expressão -2147483648 está, na verdade, aplicando o operador - à constante 2147483648 . Na sua plataforma, int não pode armazenar 2147483648 , ele deve ser representado por um tipo maior. Portanto, a expressão -2147483648 não é deduzida para ser signed int mas um tipo assinado maior, signed long int .

Como você não fornece uma sobrecarga por long o compilador é forçado a escolher entre duas sobrecargas que são igualmente válidas. Seu compilador deve emitir um erro do compilador sobre sobrecargas ambíguas.


Este é um erro muito sutil. O que você está vendo é uma consequência de não haver literais inteiros negativos em C ++. Se olharmos para [lex.icon], obtemos um literal inteiro ,

literal-inteiro
sufixo-literal inteiro-decimal
[...]

pode ser um literal decimal ,

literal-decimal:
dígito não-zero
dígito de opção decimal-literal

onde o dígito é [0-9] e o dígito diferente de zero é [1-9] e o sufixo par pode ser um dos u , U , l , L , ll ou LL . Em nenhum lugar aqui inclui - como sendo parte do literal decimal.

No §2.13.2, também temos:

Um literal de inteiro é uma sequência de dígitos que não tem parte de período ou expoente, com aspas simples separadas que são ignoradas ao determinar seu valor. Um literal inteiro pode ter um prefixo que especifique sua base e um sufixo que especifique seu tipo. O primeiro dígito lexical da sequência de dígitos é o mais significativo. Um literal inteiro decimal (base dez) começa com um dígito diferente de 0 e consiste em uma seqüência de dígitos decimais.

(ênfase minha)

O que significa que o - em -2147483648 é o operator - unário operator - . Isso significa que -2147483648 é realmente tratado como -1 * (2147483648) . Desde 2147483648 é um demais para o seu int é promovido a um long int e a ambigüidade vem de que não correspondência.

Se você quiser obter o valor mínimo ou máximo para um tipo de maneira portátil, você pode usar:

std::numeric_limits<type>::min();  // or max()




ambiguous-call