🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

1903閲覧

C++ - scoped enum 型の変数がとり得る値について

tiitoi

総合スコア21956

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

2グッド

0クリップ

投稿2019/11/22 05:27

質問内容

scoped enum 型の変数はその列挙子以外の値はとれないと認識していますが、以下の関数 func を定義すると、次の警告が出ます。

Visual Studio: 警告: C4715: 値を返さないコントロール パスがあります。
GCC: warning: control reaches end of non-void function [-Wreturn-type]

これは、なんらかの場合でどの if 文にも引っかからずに return されないケースがあるということなのでしょうか?

cpp

1enum class Type 2{ 3 A, 4 B, 5 C, 6}; 7 8int func(Type type) 9{ 10 if (type == Type::A) 11 return 1; 12 else if (type == Type::B) 13 return 2; 14 else if (type == Type::C) 15 return 3; 16} 17 18int main() 19{ 20 func(Type::A); 21}

環境

  • C++11
fana👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

scoped enum 型の変数はその列挙子以外の値はとれない

いいえ、scoped enum の変数は、underlying type として指定された整数型が取れる値なら全て取れます。

C++仕様ドラフト N3337 (2012-01-16) 7.2 Enumeration declarations の第7段落、および N4750 (2018-05-07) 10.2 Enumeration declarations の第8段落によれば

For enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type.

拙訳

underlying type が fixed な列挙型については、その列挙型の値は underlying type の値である。

ということですから、underlying type が取れる値は、すべて取れる解釈するのが自然でしょう。(ちなみに、ここでの fixed とは underlying type が指定されているという意味で、scoped enum については、省略すると int がデフォルトで指定されるので、scoped enum は、すべて fixed です。)

また、仕様ドラフトの static cast の章をみても

A value of integral or enumeration type can be explicitly converted to a complete enumeration type. If the enumeration type has a fixed underlying type, the value is first converted to that type by integral conversion, if necessary, and then to the enumeration type.

拙訳

整数型または列挙型の値は、明示的に列挙型に変換できる。もし、その列挙型が fixed な underlying type を持つならば、変換される値は、必要なら、まず、underlying type に整数型による変換を行った後、さらに目的の列挙型に変換される。

とあり、「列挙子として定義された値に限る」などの制限は言及されていません。

さらに C++ 17 では、列挙型の初期化について、以下のような拡張がなされています。

C++

1enum byte : unsigned char { }; 2byte b { 42 }; // C++ 11 ではエラー、C++ 17 では OK 3byte e { -1 }; // C++ 11 でも、 C++ 17 でもエラー

したがって、scoped enum は、列挙子として指定した値以外も取れるはずです。

投稿2019/11/22 20:37

Bearded-Ockham

総合スコア430

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/11/25 03:59

ご回答いただきありがとうございます。 scoped enum は列挙子で指定した値以外でも、基底型の値であれば取れる仕様となっているのですね。 とても参考になりました。
guest

0

scoped enum 型の変数はその列挙子以外の値はとれない

こういうパターンもあるのではないでしょうか.

c++

1enum class Type 2{ 3 A = 2, 4 B = 7, 5 C = 9, 6}; 7 8//非ローカルで,明示的に初期値を書かないとき 9Type t; //値は0で初期化されるのでは 10 11int main() 12{ 13 std::out << static_cast<int>( t ) << std::endl; 14 ... 15}

投稿2019/11/22 05:54

編集2019/11/22 06:07
fana

総合スコア11990

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/11/22 06:44 編集

ご回答ありがとうございます。 明示的に初期化していない場合の値は動作未定義みたいですね。
fana

2019/11/22 07:35

この例では外部変数としてtを書いているのでデフォルト初期化されると思う →この場合のデフォルトって何だろう? →なんだかんだで整数だし,0(static_cast<Type>(int(0))相当,というか?)になるんじゃないだろうか? …という話で,とりあえずVS2017で試した範囲では0になりました.
fana

2019/11/22 07:45

要するに,enum classでも定義した{A,B,C}だけでなく 0という値 を自然に(?)取り得るのではなかろうか? という.
tiitoi

2019/11/22 08:20

なるほど。int 等同様にデフォルトコンストラクタの場合、0で初期化されるようですね。補足していただきありがとうございます。
guest

0

enum classといえども中身は整数なので、static_castで強引に関係ない値を突っ込むことが可能でした(規約上どうなのかは確認していませんが)。

c++

1#include <iostream> 2using namespace std; 3 4enum class Type 5{ 6 A, 7 B, 8 C, 9}; 10 11int main(void){ 12 // 7つもないので範囲外の値 13 Type t = static_cast<Type>(7); 14 // いちおう「7」がそのまま返ってくる 15 cout << static_cast<int>(t) << endl; 16} 17

paiza.ioでの動作例

投稿2019/11/22 05:35

maisumakun

総合スコア145975

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/11/22 05:41 編集

static_cast で初期化子が持つ整数以外を代入するようなコードも一応通るということですね。 とりあえず最後の条件式は else にして警告が出ないようにしようと思います。 ご回答ありがとうございます。
y_waiwai

2019/11/22 05:47

あくまでもそれ以外の値は入らないことになってる、というだけですからねー
guest

0

ベストアンサー

こんにちは。

単にコンパイラが「その列挙子以外の値はとれない」ことまでチェックしていないだけと思います。
switch-caseの時は、そこまでチェックしてくれるコンパイラがいくつか有ったと思います。
if文でのそのチェックはかなり難易度高いですが、switch-caseでは容易なのです。

投稿2019/11/22 05:33

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/11/22 05:39

なるほど。コンパイラがそこまで構文解析してないということですね。 swtich ケースも試しましたが、gcc や Visual C++ では警告が出てしまいました。 ご回答いただきありがとうございます。
Chironian

2019/11/22 05:57

> コンパイラがそこまで構文解析してないということですね。 構文解析ではそこまで判断できないです。 静的解析する場合は、論理式を展開して「カルノーマップ」みたいな処理をしてdon't care領域のみreturn文に到達していることの判定を行うことになると思います。 動的に処理するなら総当りテストが必要になるでしょうが、数値を使っていると莫大な組合せが発生するので現実的な時間内では処理できないと思います。 これらは構文解析とはまた異なる分野のアルゴリズムなのです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問