最も負のint値は、あいまいな関数のオーバーロードに関するエラーを引き起こすのはなぜですか?


91

私はC ++での関数のオーバーロードについて学び、これに遭遇しました:

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

私が理解したことから、int範囲(私の場合intは4バイト)で指定された値は呼び出されdisplay(int)、この範囲外の値はあいまいになります(コンパイラーが呼び出す関数を決定できないため)。これはint、最小値を除くすべての値の範囲、つまり-2147483648エラーでコンパイルが失敗する場合に有効です。

オーバーロードの呼び出しdisplay(long int)があいまいです

しかし、同じ値をに取り、その値を出力するintと、になります2147483648。私は文字通りこの振る舞いに混乱しています。

この動作は、最も負の数が渡されたときにのみ観察されるのはなぜですか?(a short-32768- と一緒に使用された場合の動作は同じです。実際には、負の数と正の数が同じ2進数表現を持つ場合)

使用するコンパイラ:g ++(GCC)4.8.5


4
Intの最小値は「コンパイラエラーをスローしています」。どのエラー?質問に含めてください
Justin

11
なるほどcall of overloaded ‘display(long int)’ is ambiguous
crashmstr 2017

6
関連はありませんが、コンパイラを更新する必要があります。すでにGCC 7.1があります。
HolyBlackCat 2017

4
これが私の推測ですtypeof(-2147483648) != int。リテラルは2147483648であり、には大きすぎるため、でありintlong否定されています
Justin

3
興味深いことに、g ++(少なくとも6.4と7.1)int j{-2147483648};は、それがナローイング変換であると文句を言わない。それ自体、ほぼ質問に値するものです。これはおそらく、初期化でlong longconstexpr値を狭めることなどを許可することに関連し2147483647LLています。
Toby Speight 2017

回答:


145

これは非常に微妙なエラーです。あなたが見ているのは、C ++に負の整数リテラルがないことの結果です。[lex.icon]を見ると、整数リテラル

integer-literal
        decimal-literal integer-suffix opt
        [...]

decimal-literalでもかまいません。

decimal-literal:
        非ゼロ桁の
        decimal-literal ' 選択

どこの桁がある[0-9]ゼロ以外の桁がある[1-9]と接尾辞パーは、のいずれかにすることができuUlLll、またはLL。ここでは-、10進数リテラルの一部として含まれていません。

§2.13.2では、次のものも用意されています。

整数リテラルは、その値を決定する際に無視される任意の分離単一引用符で、いかなる期間または指数部を有していない数字の列です。整数リテラルには、そのベースを指定するプレフィックスとそのタイプを指定するサフィックスを含めることができます。一連の数字の字句的に最初の数字が最も重要です。A 整数リテラル(ベース10)が0以外の数字で始まり、桁の配列からなります。

(強調鉱山)

つまり、-in -2147483648は単項operator -です。つまり、-2147483648実際にはとして扱われ-1 * (2147483648)ます。21474836481つが多すぎるのでintlong intと曖昧さが一致することはないから来ています。

ポータブルな方法で型の最小値または最大値を取得したい場合は、以下を使用できます。

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

2
-2147483647 - 1負リテラル式として、警告なしに仕事もだろう
・クール

2
またはINT_MIN、最も冗長なオプションの場合。ただし、一般的ではありません。
MSalters 2017

@NathanOliver、この件について親切に説明してくださいdisplay(2147483649);。この場合、なぜunsigned int funcを呼び出せないのですか?そしてなぜそれは2147483649unsigned intではなくlong intとしてarg を扱うのですか?
無限ループ

2
@infiniteloop 10進整数リテラルから行くintまでlong intlong long intu/ U接尾辞を使用しない限り、10進数リテラルの符号なしの型を取得することはありません。
NathanOliver 2017

2
この例では、はい。電話display(unsigned a)するにはdisplay(1234u);orまたはdisplay(static_cast<unsigned>(1234));or が必要ですunsigned foo = 1234; display(foo);
NathanOliver 2017

36

-2147483648は実際に-定数に演算子を適用してい2147483648ます。ご使用のプラットフォームでintは、を格納できません2147483648。より大きな型で表す必要があります。したがって、式-2147483648signed intより大きな符号付きの型であると推定されず、signed long int

longコンパイラーにオーバーロードを提供しないため、コンパイラーは両方とも等しく有効な2つのオーバーロードから選択する必要があります。コンパイラは、あいまいなオーバーロードに関するコンパイラエラーを発行する必要があります。


4

他人の答えを拡張する


OPが混乱している理由を明確にするには、まず、以下ののsigned intバイナリ表現を検討し2147483647ます。

最大の符号付き整数




次に、この数に1を追加します。別のものsigned intを与える-2147483648(OPが使用したい) 最小の符号付き整数



最後に、32ビットに収まるので、OPが-2147483648long int代わりににコンパイルすると、OPが混乱する理由がわかりsigned intます。

ただし、現在の回答で述べられているように、単項演算子(-)は、32ビットに収まらないaの解決後に適用さます。2147483648long int

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.