web-dev-qa-db-fra.com

Pourquoi la valeur int la plus négative provoque-t-elle une erreur concernant les surcharges de fonctions ambiguës?

J'apprends la surcharge de fonctions en C++ et je suis tombé sur ceci:

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);
}

D'après ce que j'ai compris, toute valeur donnée dans la plage int (dans mon cas, int est égale à 4 octets) appellera display(int) et toute valeur en dehors de cette plage sera ambiguë (car le compilateur ne peut pas décider quelle fonction appeler). Il est valide pour la plage complète de int valeurs, à l'exception de sa valeur minimale, à savoir -2147483648, Où la compilation échoue avec l'erreur.

l'appel de surchargé display(long int) est ambigu

Mais en prenant la même valeur sur un int et en imprimant la valeur, on obtient 2147483648. Je suis littéralement confondu avec ce comportement.

Pourquoi ce comportement est observé uniquement lorsque le nombre le plus négatif est passé? (Le comportement est le même si un short est utilisé avec -32768 - en fait, dans tous les cas où le nombre négatif et le nombre positif ont la même représentation binaire)

Compilateur utilisé: g ++ (GCC) 4.8.5

88
infinite loop

C'est une erreur très subtile. Ce que vous voyez est une conséquence de l'absence de littéraux entiers négatifs en C++. Si nous regardons [Lex.icon], nous obtenons qu’un entier-littéral ,

entier-littéral
suffixe entier littéral décimalopt
[...]

peut être un décimal-littéral ,

littéral décimal:
chiffre différent de zéro
decimal-literal ’ opt chiffre

chiffre est [0-9] et chiffre différent de zéro est [1-9] Et le suffixe par peuvent être l'un de u, U, l, L, ll, ou LL. Nulle part ici n'inclut - Comme faisant partie du littéral décimal.

Au §2.13.2, nous avons aussi:

Un littéral entier est une séquence de chiffres qui ne comporte aucune période ni partie d'exposant, avec une séparation facultative des guillemets simples qui sont ignorés lors de la détermination de sa valeur. Un littéral entier peut avoir un préfixe qui spécifie sa base et un suffixe qui spécifie son type. Le premier chiffre lexicalement de la séquence de chiffres est le plus significatif. A décimal le littéral entier (base dix) commence par un chiffre autre que 0 et consiste en une séquence de chiffres décimaux.

(c'est moi qui souligne)

Ce qui signifie que - Dans -2147483648 Est le unaire operator -. Cela signifie que -2147483648 Est en fait traité comme -1 * (2147483648). Puisque 2147483648 Est un de trop pour votre int, il est promu en long int Et l'ambiguïté vient de ce qui ne correspond pas.

Si vous souhaitez obtenir la valeur minimale ou maximale d'un type de manière portable, vous pouvez utiliser:

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

L'expression -2147483648 applique réellement le - opérateur à la constante 2147483648. Sur votre plate-forme, int ne peut pas stocker 2147483648, il doit être représenté par un type plus grand. Par conséquent, l'expression -2147483648 _ n'est pas déduit pour être signed int mais un type plus gros signé, signed long int.

Comme vous ne fournissez pas de surcharge pour long, le compilateur est obligé de choisir entre deux surcharges ayant la même validité. Votre compilateur devrait générer une erreur de compilation à propos de surcharges ambiguës.

36
François Andrieux

Développer les réponses des autres


Pour clarifier la raison pour laquelle le PO est confus, d’abord : considérons le signed int représentation binaire de 2147483647, au dessous de.

Largest signed int




Ensuite, ajoutez un à ce nombre : donnant un autre signed int de -2147483648 (que le PO souhaite utiliser) Smallest signed int



Enfin: nous pouvons voir pourquoi le PO est confus quand -2147483648 compile en un long int au lieu d'une signed int, car il correspond clairement à 32 bits.

Mais, comme le mentionnent les réponses actuelles, l'opérateur unaire (-) est appliqué après résolvant 2147483648 qui est un long int et ne correspond PAS à 32 bits.

4
bunkerdive