NF

地方で働くプログラマ

やさしいconstexpr(2)

やさしいconstexpr(1) - NF
つづきです

関数にconstexprを指定する

変数にconstexprを指定するように、関数にもconstexprを指定できる。
前回、実行時定数にconstexprを指定してコンパイル時定数にしたので、今回はコンパイル時定数を返す関数を考える。

#include <iostream>
class MyArray{
public:
    MyArray() = delete;  // デフォルトコンストラクタは使わない
    MyArray(const size_t size) : N(size) {}
    size_t size() const { return N; }
    const size_t N;
};
int main() {
    const MyArray x(10);
    int arr[x.size()] = {1};
}

MyArrayのサイズはコンパイル時に分かるはずだが、MyArray.size()はコンパイル時定数ではないので、前回の最初の例と同じく「int a[arr.size()] 」の宣言はコンパイルエラーになる。
これも、MyArray型変数の宣言をconstからconstexprに変えて、MyArray.size()にconstexprを指定する事でコンパイルが・・・通りませんでした。なんで?

#include <iostream>
class MyArray{
public:
    MyArray() = delete;  // デフォルトコンストラクタは使わない
    MyArray(const size_t size) : N(size) {}
    constexpr size_t size() const { return N; }
    const size_t N;

};
int main() {
    constexpr MyArray x(10);
    int arr[x.size()] = {1};
}
main.cpp: In function 'int main()':
main.cpp:11:27: error: call to non-'constexpr' function 'MyArray::MyArray(size_t)'
   11 |     constexpr MyArray x(10);
      |                           ^
main.cpp:5:5: note: 'MyArray::MyArray(size_t)' declared here
    5 |     MyArray(const size_t size) : N(size) {}
      |     ^~~~~~~
main.cpp:12:9: warning: ISO C++ forbids variable length array 'arr' [-Wvla]
   12 |     int arr[x.size()] = {1};
      |         ^~~

MyArray型変数をconstexpr指定で生成してるのに、MyArrayのコンストラクタがconstexpr指定されてないよ、とのこと(合ってる?)。確かに。と言う訳で、MyArrayのコンストラクタにconstexprを指定すると無事にコンパイルが通りました。
 
以上のように、関数にconstexprを指定することで定数を使える幅が広がりました。



補足(?):定数が使えない場合に起こること

前回今回と、constexprによってコンパイル時に決まる値を配列サイズに使えるようになった話を書きましたが、定数として使えない時に(実際に)起こった事を書きます。

  • 直値を使う
  • コメントで補足(「// x.size()と同じ値にすること」みたいな)して直値を使う
  • プリプロセッサでx.size()と同じ値を定義する
  • コンパイル時の警告オプションをこっそり外す

補足ではなく愚痴でした。
2023年にもなってこんな事書いてるの自分くらいだと思った。

つづく