web-dev-qa-db-ja.com

なぜ「自動」は単項マイナス演算子を尊重しないのですか?

私はC++を初めて使用しますが、autoのこの動作がおかしいと感じています。

class A{};

int main() {
    A a;
    auto x = -(sizeof(a));
    cout << x << endl;
    return 0;
}

この場合、変数xはunsignedです。ただし、変数の初期化で単項マイナス演算子を使用しました。戻り値の型がsizeofstd::size_t)は考慮されますが、使用される演算子のために格納された数値が負になるという事実ではありませんか?

私はsize_tは符号なし整数です。

GCC 8.1.0とC++ 17でこれを試しました。

32
CodeShark

ここでの実際の問題は、他の組み込み算術演算子と同様に、単項マイナス演算子の使用が積分プロモーションの対象であることです。意外なことに、size_tに単項マイナスを適用した結果はsize_tのままであり、autoを非難する必要はありません。

反例。この場合、整数のプロモーションにより、xのタイプはintになるため、出力は-1になります。

unsigned short a{1};
auto x{-a};
cout << x << endl;
28
VTT

-(sizeof(a))は、単項-演算子を符号なし型の値に適用します。単項-演算子は、符号なし整数値を符号付き整数値に変換しません。むしろ、そのような演算の結果となる符号なしの値を次のように定義します(cf. cppreference.comの単項算術演算子 )。

組み込みの単項マイナス演算子は、昇格したオペランドの否定を計算します。符号なしaの場合、-aの値は2 ^ b -aです。ここで、bは昇格後のビット数です。

したがって、たとえ驚くかもしれないとしても、単項-演算子を符号なしの値に適用した結果は依然として符号なしの値であるため、autoは正しく機能します。

21
Stephan Lechner

(単項)-を符号なしの値に適用した結果は符号なしであり、sizeofは符号なしの値を返します。

単項演算子のオペランドは、算術またはスコープなしの列挙型である必要があり、結果はそのオペランドの否定です。積分プロモーションは、整数または列挙オペランドで実行されます。符号なしの量の負の値は、2 ^ nからその値を減算することによって計算されます。ここで、nはプロモートオペランドのビット数です。結果のタイプは、昇格されたオペランドのタイプです。

[expr.unary.op]

sizeofおよびsizeof...の結果は、std​::​size_­t型の定数です。

[expr.sizeof]

実装定義の動作を回避するには、-を適用する前にintに変換する必要があります

宛先タイプが署名されている場合、値は宛先タイプで表現できる場合は変更されません。それ以外の場合、値は実装定義です。

[conv.integral]

class A{};

int main() {
    A a;
    auto x = -(int{sizeof(a)});
    cout << x << endl;
    return 0;
}
4
Caleth

https://en.cppreference.com/w/cpp/language/sizeof を見ると、結果はsize_tタイプで、unsignedです。負の値を許可するには、明示的にsigned intとして宣言する必要があります。

autoの代わりに、負の値を許可するintを書くことができます。

1