2024年8月19日月曜日

c++でstatic constなclass member変数としてfloat型を定義したい場合はconstexprを使う


遭遇したエラーとconstexprを利用した回避

class memberのstatic constなfloat型を定義するとエラーが発生しました。
class Sample0 {
public:
static const float staticConstFloat0 = 0.5;
};
main.cpp:7:22: error: ‘constexpr’ needed for in-class initialization of static data member ‘const float Sample0::staticConstFloat0’ of non-integral type [-fpermissive]
5 | static const float staticConstFloat0 = 0.5;
| ^~~~~~~~~~~~~~~~~

エラーの内容に従いconstをconstexprに置き換えると回避できました。(初めて遭遇した時は解消方法が分からず一旦constを使わないことで回避しました。)
class Sample0 {
public:
static constexpr float staticConstFloat0 = 0.5;
};

constexprて何なん?c++11から導入されたビルド時に値が決まる変数や関数を定義する表現

cppのconstesprの日本語説明によるとmax()が関数なためビルド時に評価できなくて不都合な場面があったため導入された表現らしいです。

constで定義した変数は実行時に値が変わらないものなのに対しconstexprはそれが関係する変数や関数の処理はビルド時に評価されるため、constよりconstexprの方が処理時間を短く出来る場合があるようです。

intは良いのにfloatやdoubleはstatic const class memberになれないのはなぜ?class memberの仕様らしい

下記のコードをビルドするとclass内のstatic const floatがエラーになります。
class Sample2 {
public:
static const int staticConstInt = 5;
static const long staticConstLong = 4;
static const float staticConstFloat = 0.5; // ここがエラーになる
};

static const float vFloat = 0.5; // ここはビルドされる

static const floatは良くてclass memberのstatic const floatがエラーになるのが自分には解せませんが、c++として「class memberはconstant initializerを持っているものしかstatic memberになれない」(C++ Standard Section 9.2)仕様らしいです。

constexprが導入された理由のようにfloatやdoubleなどの浮動小数点の初期化時に関数が呼び出されて条件から外れるのだと推測します。

参考
Why aren't static const floats allowed?

おわり

floatのclass member static constを定義する場合はconstをconstexprに変えれば期待通りに初期化できると分かりました。
class memberではないstatic const floatは定義できたので不思議でしたが、class memberの仕様と認識しました。
constよりconstexprを使う方がビルド時に評価されて処理が早くなることがあるらしいので、constexprを積極的に使ってみます。

0 件のコメント :