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

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

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

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

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

Q&A

解決済

1回答

5241閲覧

ヘッダファイル内でconstexprの定数定義をすることの問題点、複数ファイルで使用したい定数の定義方法

tuyudaku

総合スコア75

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

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

0グッド

0クリップ

投稿2019/10/29 05:02

現在下記のようなソースコードに対して、
静的解析ツールから指摘が出ています。

C++

1// header.h 2namespace TMP_NAME 3{ 4static constexpr quint8 TEISU_A = 10; // この行に対して指摘 5static constexpr quint8 TEISU_B = 20; // この行に対して指摘 6} 7

指摘内容は以下になります。

ヘッダファイル内で領域獲得をしています。(変数"TEISU_A") ヘッダファイル内で領域獲得をしています。(変数"TEISU_B")

指摘の詳細説明については以下になります。

[意味]   ソースファイルから#include文で取り込まれたインクルードファイルで、領域獲得の変数定義あるいは関数定義を行っています。  インクルードファイルは、複数のソースファイルから取り込まれることを前提にしたファイルです。  このためインクルードファイルで領域獲得を行うと、外部変数や普通の関数の場合はリンクエラーが発生します。  また、静的変数や静的関数の場合は複数の領域が確保されてしまいます。 [対処方法]   複数のファイルで共通に使用する変数や関数の場合、インクルードファイルではextern変数宣言や関数宣言を行い、1つのソースファイルで領域獲得の変数定義や関数定義を行いましょう。   1つのファイルで使用する変数や関数の場合は、インクルードファイルでの変数定義や関数定義は削除し、ソースファイル毎に領域獲得するstatic変数定義やstatic関数定義を記述しましょう。

まず、この静的解析ツールの注意点として、C++11以上に対応できていないため、
C++11から追加されたキーワードや構文を認識できません。
なのでC++11以上の機能については誤指摘が発生するという問題があります。

その上で、指摘の詳細説明については十分に理解して、確かにその通りでヘッダ内で領域確保は問題だろうな
とは思ったのですが。
今回指摘が出ている部分はC++11からの機能であるconstexprについてのため
この指摘が本当に適用されるものなのか、無視しても問題ないものなのかということについて悩んでいるところです

**constexprは(可能なものであれば)コンパイル時定数として扱われて、領域というものが無いと思っていたので、
この指摘は無視しても大丈夫なのか?**と悩んでいます。
これがコンパイル時定数として扱われないものなのであれば、指摘は無視できないでしょうが
今回のconstexprの使用用途はただの定数定義あるため、基本的にはコンパイル時定数として扱われるだろうと思っておりますが、
知識が浅いため判断することが出来ません...
このソースコードに対しての指摘は、無視しても大丈夫なものなのかどうか
分かる方がいらっしゃいましたら教えていただけませんでしょうか?

また、今回のようにヘッダファイル内に直接constexprで定数定義しているのは
単純に、全体で使えるような定数を定義したかったからなのですが
このような使用方法、定義方法は一般的には有りなのか無しなのかを知りたいです。

もし全体で使用する定数を定義する場合でも
それ用のクラスを用意してその中に定義をするべきなのかどうかなども悩んでいます。
皆さんのコーディング方法などを聞いてお勉強させてください

よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

ツールによる constexpr に関する指摘は真っ当なものです。

constexpr はコンパイル時計算「できる」ことを示唆するもので、必ずするわけではないです。 変数に対する constexpr 指定は const と大差ありません。 (なので C++20 では consteval という強固な指定方法が追加されました。) 数値に置き換えるような最適化がされる可能性は高いですがあくまでも変数です。

質問中の例のような TEISU_A TEISU_B は各コンパイル単位ごとに確保される変数であり、内容が同じ変数が各コンパイル単位に作られることを意味します。 内容が同じなので単なる整数の別名として定義するのであれば問題として顕現することはたぶんありません。 そういう意味では問題ないです。

しかし、結果的に問題はないといっても意図しているのはプログラム全体で唯一の値ということでしょうから、そういう意味では誤りですし、もし TEISU_A TEISU_B のアドレスを取ろうとすれば、その結果はコンパイル単位ごとに違う値になります。

C++17 からならば inline 変数を使うべしと言い切ってしまえるのですが、 C++11 だと定数の定義をどうすべきなのかというのはなかなか微妙な話で、なんだかんだで #define で定義するのが楽というのが現実です。

#define では namespace に入れられませんので、 namespace 中で quint8 型の整数定数を定義するという条件に合うようにするには enum を用いる方法が考えられます。

cpp

1namespace TMP_NAME 2{ 3 enum : quint8 { TEISU_A = 10, TEISU_B = 20 }; 4}

投稿2019/10/29 06:19

編集2019/10/29 08:31
SaitoAtsushi

総合スコア5444

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

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

tuyudaku

2019/10/29 08:46

>ツールによる constexpr に関する指摘は真っ当なものです。 そうですか... 修正をしていきたいと思います クラスのメンバ変数として定義すると質問の指摘が出てこなくなるので とりあえずその方向で行こうかなと思っています ちょっと雑な修正ではありますが... >なんだかんだで #define で定義するのが楽というのが現実です。 やっぱりそうですよね,,, 頑張ってdefineを使わずに行くぞ!とやっているのですが defineだと楽だな...って思うことが多々あります... >namespace 中で quint8 型の整数定数を定義するという条件に合うようにするには enum を用いる方法が考えられます。 基底型を指定してenumを定義したかったのですが どうも思ったとおりの動作をしてくれず断念をしていました 使い方が悪いのか、私がやりたいやり方ではダメなのか... enumを使ったやり方も検討していきたいと思います 回答ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問