C ++列挙型は署名されていますか、署名されていませんか?そして、拡張によって、それが<=あなたの最大値であることを確認することによって入力を検証し、> =あなたの最小値を除外することは安全です(0から開始し、1ずつ増加したと仮定します)?
C ++列挙型は署名されていますか、署名されていませんか?そして、拡張によって、それが<=あなたの最大値であることを確認することによって入力を検証し、> =あなたの最小値を除外することは安全です(0から開始し、1ずつ増加したと仮定します)?
回答:
特定の表現に依存するべきではありません。次のリンクを読んでください。また、標準では、列挙型の基本型として使用される整数型は実装定義であると述べていますが、ある値がintまたはunsigned intに収まらない場合を除いて、intより大きくなることはありません。
つまり、列挙型が署名されているか、署名されていないかに依存することはできません。
ソースに行きましょう。C ++ 03標準(ISO / IEC 14882:2003)ドキュメントの7.2-5(列挙宣言)の内容は次のとおりです。
列挙型の基になる型は、列挙型で定義されているすべての列挙子の値を表すことができる整数型です。列挙型の値がintまたはunsigned intに収まらない場合を除いて、基になる型がintより大きくならないことを除いて、列挙型の基になる型として使用される整数型は実装定義です。
要するに、コンパイラーが選択することになります(明らかに、列挙値の一部に負の数がある場合は、署名されます)。
署名されているか、署名されていないかに依存するべきではありません。それらを明示的に署名または署名なしにする場合は、以下を使用できます。
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
署名されているか署名されていないかに依存しないでください。標準によれば、列挙型の基礎となる型として使用される整数型は実装定義です。ただし、ほとんどの実装では、符号付き整数です。
C ++ 0xでは、強く型付けされた列挙が追加され、次のような列挙型を指定できます。
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
ただし、今でも、次のように列挙型を変数またはパラメーターの型として使用することで、簡単な検証を行うことができます。
enum Fruit { Apple, Banana };
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit
// even though it has the same value as banana.
コンパイラは、列挙型が署名されているかどうかを判断できます。
enumを検証する別の方法は、enum自体を変数タイプとして使用することです。例えば:
enum Fruit
{
Apple = 0,
Banana,
Pineapple,
Orange,
Kumquat
};
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana.
いくつかの古い回答でさえ44票を得ましたが、私はそれらすべてに反対する傾向があります。つまり、underlying type
列挙型について気にする必要はないと思います。
まず、C ++ 03 Enum型は、符号の概念がない独自の型です。C ++ 03標準以降dcl.enum
7.2 Enumeration declarations
5 Each enumeration defines a type that is different from all other types....
したがって、列挙型の符号について話しているとき、たとえば<
演算子を使用して2つの列挙型オペランドを比較しているとき、実際には列挙型をある整数型に暗黙的に変換することについて話している。重要なのは、この一体型のしるしです。そして、列挙型を整数型に変換するとき、このステートメントが適用されます:
9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).
そして、どうやら、列挙型の基礎となるタイプはIntegral Promotionとは何の関係もありません。規格では次のようにIntegral Promotionが定義されているため、
4.5 Integral promotions conv.prom
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long.
だから、列挙型になるかどうsigned int
かunsigned int
かどうかに依存してsigned int
定義され列挙子、ない列挙型の基になる型のすべての値を含めることができます。
関連する質問を参照してください 整数型に変換した後のC ++列挙型の符号が正しくない
-Wsign-conversion
。これは、コード内の意図しない間違いを見つけるのに役立ちます。ただし、標準を引用し、列挙型に関連付けられている型(対)がないことを指摘する場合は+1。signed
unsigned
将来、C ++ 0xでは、強く型付けされた列挙が使用可能になり、いくつかの利点(型の安全性、明示的な基本型、明示的なスコープなど)が提供されます。これにより、タイプの記号をより確実に確認できます。
署名済み/署名なしについて他の人がすでに言ったことに加えて、列挙型の範囲について標準が言っていることは次のとおりです:
7.2(6):「e(min)が最小の列挙子であり、e(max)が最大の列挙型の場合、列挙型の値は、b(min)からb(max)の範囲の基になる型の値です。 )、ここで、b(min)とb(max)はそれぞれ、e(min)とe(max)を格納できる最小ビットフィールドの最小値と最大値です。定義されていない値を持つ列挙を定義することは可能ですその列挙子のいずれかによって。」
だから例えば:
enum { A = 1, B = 4};
e(min)が1でe(max)が4の列挙型を定義します。基になる型がintに署名されている場合、必要な最小のビットフィールドは4ビットであり、実装のintが2の補数の場合、有効な範囲は列挙型は-8〜7です。基になる型が符号なしの場合、3ビットで、範囲は0〜7です。気になる場合は、コンパイラのドキュメントを確認してください(たとえば、列挙子以外の整数値を列挙型の場合、値が列挙の範囲内にあるかどうかを知る必要があります-結果の列挙値が指定されていない場合は)。
これらの値が関数への有効な入力であるかどうかは、列挙型の有効な値であるかどうかとは異なる問題になる可能性があります。チェックコードはおそらく後者ではなく前者を心配しているため、この例では少なくとも> = Aおよび<= Bをチェックする必要があります。
std::is_signed<std::underlying_type
+スコープ付き列挙型でデフォルトをチェックするint
https://en.cppreference.com/w/cpp/language/enumは以下を意味します:
main.cpp
#include <cassert>
#include <iostream>
#include <type_traits>
enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};
int main() {
// Implementation defined, let's find out.
std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;
// Guaranteed. Scoped defaults to int.
assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));
// Guaranteed. We set it ourselves.
assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}
コンパイルして実行:
g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main
出力:
0
Ubuntu 16.04、GCC 6.4.0でテスト済み。