読者です 読者をやめる 読者になる 読者になる

ボレロ村上 - ENiyGmaA Code

中3女子です。

constexpr を使うべき5の理由 - その2


引き続き、「constexpr を使うべき5の理由」です。
ここでは、できるかぎり関数に constexpr を付けることが如何に C++er の義務であるかを示します。


2.定数を返す関数をコンパイル時定数にする
#include <limits>

constexpr auto v = std::numeric_limits<double>::max();

std::numeric_limits は、標準ライブラリで constexpr が使われた例として最も有名なものの一つでしょう。


C++03 では浮動小数点型の定数を定義することできなかったため、numeric_limits::min/max を関数として定義せざるをえず、
関数であるがゆえその値をコンパイル時定数として使うことができなかった。
C++11 では関数が constexpr 指定されたため、返値をコンパイル時定数として使うことができるようになった。


このことはよく知られている C++03 の「失敗」であり、constexpr がそれを完全に補っている。
あなたは、自明な定数値を返すような関数については、それがフリー関数であれメンバ関数であれ、constexpr 指定すべきです。

template<typename T, size_t N>
struct MyArray {
    T elem[N];
    size_t size() { return N; }
};

例えば以上のようなメンバ関数を見たら、C++er であるあなたは必ずこう言うでしょう。
「!!!const が付いてないぞ!!!」と。

template<typename T, size_t N>
struct MyArray {
    T elem[N];
    size_t size() const { return N; }
};

あなたが原理主義的な const 教徒であるかそうでないかにかかわらず、このような関数には必ず const をつけるべきです。
理由はここで述べるまでもありませんが、それが C++ プログラムとしての「正しさ」です。

template<typename T, size_t N>
struct MyArray {
    T elem[N];
    constexpr size_t size() const { return N; }
};

メンバ関数に(可能な限り) const を付けるのが正しいのと全く同じく、メンバ関数に constexpr を付けることは正しい
コードの挙動をまったく変えることなく、それをコンパイル時に実行できるようにする。
少なくともこのようなケースにおいて、プログラムの意図が明確になり、それを必要とする者にとってより便利になり、そしてデメリットはおよそ無いからである。


なるほど、世の中にはひょっとして(考えたくもないことだが)ある関数が read-only や immutable であることの言語による強制など窮屈なだけで必要としないという罪深い人間がいるかもしれない。
ちょうど、どんな国にもアナーキスト売国奴が少なからず存在するように。


であっても、少なくとも国家はアナーキスト売国奴のために存在するものではない。
関数が read-only かつ immutable であるという安全保障を必要とする善良な市民がいることを慮って const を書くように、
それをコンパイル時に必要とする善良な市民がいることを想像すれば、constexpr を書くことが正しい義務であると理解できるはずです。


「市民、あなたは constexpr ですか」
「もちろんです、C++。constexpr であることは市民の義務です」