私はC++を初めて使用しますが、auto
のこの動作がおかしいと感じています。
class A{};
int main() {
A a;
auto x = -(sizeof(a));
cout << x << endl;
return 0;
}
この場合、変数xはunsigned
です。ただし、変数の初期化で単項マイナス演算子を使用しました。戻り値の型がsizeof
(std::size_t
)は考慮されますが、使用される演算子のために格納された数値が負になるという事実ではありませんか?
私はsize_t
は符号なし整数です。
GCC 8.1.0とC++ 17でこれを試しました。
ここでの実際の問題は、他の組み込み算術演算子と同様に、単項マイナス演算子の使用が積分プロモーションの対象であることです。意外なことに、size_t
に単項マイナスを適用した結果はsize_t
のままであり、auto
を非難する必要はありません。
反例。この場合、整数のプロモーションにより、x
のタイプはint
になるため、出力は-1
になります。
unsigned short a{1};
auto x{-a};
cout << x << endl;
式-(sizeof(a))
は、単項-
演算子を符号なし型の値に適用します。単項-演算子は、符号なし整数値を符号付き整数値に変換しません。むしろ、そのような演算の結果となる符号なしの値を次のように定義します(cf. cppreference.comの単項算術演算子 )。
組み込みの単項マイナス演算子は、昇格したオペランドの否定を計算します。符号なしaの場合、-aの値は2 ^ b -aです。ここで、bは昇格後のビット数です。
したがって、たとえ驚くかもしれないとしても、単項-
演算子を符号なしの値に適用した結果は依然として符号なしの値であるため、auto
は正しく機能します。
(単項)-
を符号なしの値に適用した結果は符号なしであり、sizeof
は符号なしの値を返します。
単項演算子のオペランドは、算術またはスコープなしの列挙型である必要があり、結果はそのオペランドの否定です。積分プロモーションは、整数または列挙オペランドで実行されます。符号なしの量の負の値は、2 ^ nからその値を減算することによって計算されます。ここで、nはプロモートオペランドのビット数です。結果のタイプは、昇格されたオペランドのタイプです。
sizeof
およびsizeof...
の結果は、std::size_t
型の定数です。
実装定義の動作を回避するには、-
を適用する前にint
に変換する必要があります
宛先タイプが署名されている場合、値は宛先タイプで表現できる場合は変更されません。それ以外の場合、値は実装定義です。
class A{};
int main() {
A a;
auto x = -(int{sizeof(a)});
cout << x << endl;
return 0;
}
https://en.cppreference.com/w/cpp/language/sizeof を見ると、結果はsize_t
タイプで、unsigned
です。負の値を許可するには、明示的にsigned int
として宣言する必要があります。
auto
の代わりに、負の値を許可するint
を書くことができます。