質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C++

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

Q&A

解決済

3回答

53785閲覧

C++で定数を宣言するときの方法について

yama_da

総合スコア73

C++

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

1グッド

1クリップ

投稿2017/02/16 05:44

編集2017/02/16 05:48

こんにちは。

今まで僕は何気なく実装ファイルの上の方にconst修飾子をつけて定数を宣言していましたが、本当にこれで良いのでしょうか?

C++

1const std::string CONST_STR("const_string"); 2const int CONST_NUM = 100;

検索してみると、こちらのサイトを見つけました。ここによると、以下のようにヘッダに宣言を書いて、

C++

1struct CConstParam 2{ 3 static const int RETCODE_SUCCESS; 4 static const int RETCODE_FAIL; 5 static const int RETCODE_WARN; 6};

実装ファイルに実体と初期値を定義する(以下)とあるのですが、

C++

1const int CConstParam::RETCODE_SUCCESS = 0; 2const int CConstParam::RETCODE_FAIL = 1; 3const int CConstParam::RETCODE_WARN = 2;

この方法は最初の方法となにが違うのでしょうか?他のクラスから参照できるかどうかということでしょうか?
また、クラス内だけで使う定数なら最初の方法で問題ないのでしょうか?

kikurage👍を押しています

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

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

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

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

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

t_obara

2017/02/16 05:58

参考にされたページの意図はご理解されたのでしょうか?
guest

回答3

0

ベストアンサー

実装ファイルの上の方にconst修飾子をつけて定数を宣言していましたが、本当にこれで良いのでしょうか?

C++

1const std::string CONST_STR("const_string"); 2const int CONST_NUM = 100;

大きく間違ってはいませんが、他の実装ファイルにたまたま同名の定数が存在すると、リンク時にエラーが発生するはずです(「同名エンティティが重複して存在する」といったニュアンスのメッセージになります)。

ある実装ファイル内部でしかその定数を使わないのであれば、定数宣言時にstatic修飾を行うか、無名名前空間に配置するか、あるいはその両方を行って下さい。

C++

1static const int CONST_NUM = 100; 2// または 3namespace { 4const int CONST_NUM = 100; 5}

以下のようにヘッダに宣言を書いて(中略)実装ファイルに実体と初期値を定義するとあるのですが、
この方法は最初の方法となにが違うのでしょうか?他のクラスから参照できるかどうかということでしょうか?

大きな違いは「コンパイル時定数か?」という点です。具体例の一つとして「配列の要素数として指定できるか否か」という違いがあります。前者CONST_NUMint a[CONST_NUM]のように使えますが、後者はヘッダファイルをincludeしただけの実装ファイルでint b[CConstParam::RETCODE_WARN]としてもコンパイルエラーとなるはずです。

(注:その定数値が配列の要素数として意味があるかという観点は無視してください。あくまでもコンパイル定数の例示としてそのまま変数名を拝借しているだけです。)

投稿2017/02/16 08:39

yohhoy

総合スコア6191

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

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

KSwordOfHaste

2017/02/16 08:51

> `int b[CConstParam::RETCODE_WARN]`としてもコンパイルエラー 自分もそう思ったのですが、やってみるとコンパイルエラーにならず期待通りに初期化できるようでした(cygwin上のg++ (GCC) 5.4.0)。はっきりとはわかりませんが、昔の仕様ではNGで最新の仕様がOKになったのか昔からOKだったのか自分にはわかりません。勘違いだったらご容赦です。
yohhoy

2017/02/16 09:13 編集

手元のCygwin/gcc 6.3.0だと "array bound is not an integer constant before ‘]’ token" のようなコンパイル時エラーになりますね。私の理解の範囲内では、コンパイラの最適化レベルとは無関係に、後者はコンパイルエラーとなるべきです。 ---a.h--- struct A { static const int N; }; --a.cpp-- const int A::N = 10; --main.cpp-- #include "a.h" int main() { int a[A::N]; }
Chironian

2017/02/16 09:35

KSwordOfHasteさんがトライされた姿はVLAだったりしないでしょうか? C++の規格上はVLAを使えない筈ですが、gccはC++でも使えたと思います。
KSwordOfHaste

2017/02/16 10:10 編集

そうでしたか!g++ 5.4.0にはそんな落とし穴が!?言語仕様を調べてみようと思います。コメントありがとうございました。(これはg++のバージョンの違いだと思ったコメントでしたが・・・) => ChironianさんコメントによりVLAの存在を初めて知りました!そこ確認してみます。お二方ともありがとうございました! => 「Array Extension TS(VLAが入る予定だった?)がC++14で取り下げられた」という記事を見つけました(多分yohhoyさんのサイトのようです)! 少なくともgcc 5.4.0でオプションなしや-std=c++14としても警告なしにVLAが使えるようで-WvlaとしないとVLA使用に気づけないことも分かりました。-Wvlaとするとちゃんと警告されました! お手数をおかけしてしまいすみませんでした。
yohhoy

2017/02/16 10:52

なるほどVLA(がC++でも使えちゃうGNU拡張)なら納得です。thanks!
guest

0

クラス/構造体の内側に定数を置くかグローバルな定義として置くかは定数定義の性質次第かと思います。

値定義を宣言と同時にするか宣言と定義を分離するかについては・・・

参考にされたページには「ヘッダーに直接定数を書くとそのヘッダーを修正して定数を変更すると参照しているヘッダーをincludeしているソースを全部コンパイルしなおさないといけない」と書いてあります。

開発中に調整したいような定数の場合はそうしたことを意識して定数の定義をソースファイルへ置いておくとコンパイル範囲を制限できるので便利といえるでしょう。ではヘッダーへ定数を書くとよくないかというと利点はあると思います。それはヘッダーに書いた定数はソースをコンパイルした時点で確定しているため値を参照した際にコンパイラーが最適化してくれると期待できるからです。

例えば以下のようなソースをコンパイルしてみると・・・

---a.h--- class A { public: static const int N; static const int M = 10; } --a.cpp-- const int A::N = 10; --main.cpp-- #include "a.h" ... int v1 = A::N; int v2 = A::M; $ g++ -g -S main.cpp -- main.s -- ... ;以下の3行がv1への代入 .loc 1 9 0 movq .refptr._ZN1A1NE(%rip), %rax ; Nのアドレスをraxへ入れ movl (%rax), %eax ; raxの中身をeaxへ入れ movl %eax, -20(%rbp) ; eaxの中身をローカル変数v1へ設定 ;以下の1行がv2への代入 .loc 1 10 0 movl $10, -24(%rbp) ; 値10を直接ローカル変数v2へ設定

のようにNは実際に定数値が入っている変数Nの中身を参照するコードが生成されるのに対してMは定義した値10がそのままリテラルとしてコンパイルされていることが伺えます。

投稿2017/02/16 07:10

編集2017/02/16 07:13
KSwordOfHaste

総合スコア18394

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

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

0

ファイル内でしか使わない定数であれば、前者の方法にさらにstaticを冠して、static const int ...のように定義しましょう。

staticがない場合、別なファイルに同じ定数があると衝突してしまいます。

あと、constexprの使えるコンパイラであれば、後者のようなクラス定数をconstexprとすることで、クラス内で定義してしまえます(参考)。

投稿2017/02/16 06:03

maisumakun

総合スコア145183

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問