- cpp20[meta cpp]
このページはC++20に採用された言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
C++20では、関数またはメンバ関数に対して、consteval
キーワードで常に定数式評価されるよう指定できる。そのような関数を即時関数(immediate function)という。
constexpr
と似ているが、constexpr
を付けた関数はコンパイル時にも実行時にも評価できるのに対し、consteval
の場合は必ずコンパイル時に評価される点が異なる。
consteval
指定子の付いた関数(即時関数)は、定数式評価されない場合はエラーとなる。
// P1073R3より引用
consteval int sqr(int n) {
return n*n;
}
constexpr int r = sqr(100); // OK
int x = 100;
int r2 = sqr(x); // エラー: 定数式評価されない
ただし、他の即時関数の中では、即時関数が定数式評価されなくてもエラーとはならない。これは、呼び出し元が即時関数であれば、結局はコンパイル時に評価されるからである。
// P1073R3より引用
consteval int sqrsqr(int n) {
return sqr(sqr(n)); // ここでは定数式ではないがOK
}
constexpr int dblsqr(int n) {
return 2*sqr(n); // エラー: 定数式評価されず、呼び出し元が即時関数ではない
}
即時関数のポインタを取得することはできない。
// P1073R3より引用
using Int2Int = int(int);
Int2Int *pf = sqr; // エラー
定数式として評価できない部分があっても、評価しようとしなければエラーとならない。
consteval void f(int n) {
if(n < 0) {
throw "n should not be negative"; // throwは定数式として評価できないが、ここを通らなければOK
}
}
int main() {
f(10); // OK
f(-1); // エラー
}
この性質は様々なチェックをコンパイル時に行うために活用できる。たとえば、std::format
におけるコンパイル時の書式文字列チェックで使用されている。
// P1073R3より引用
consteval int sqr(int n) {
return n*n;
}
constexpr int r = sqr(100); // OK
int main(){
static_assert(r == 10000, "100 * 100 == 10000");
// int x = 100;
// int r2 = sqr(x); // エラー: 定数式評価されない
}
C++11で導入されたconstexpr
指定子によって、関数を定数式評価できることを表明できるようになった。しかし、constexpr
関数は定数式評価しないで実行時に評価することもできる。
それに対して、関数形式のマクロを置き換えたいであるとか、単に定数式以外では用途がない関数であるなどの理由で、必ず定数式評価される関数を作りたいという要求があり、即時関数が導入されることになった。
即時関数は実行時に評価できず、アドレスを取ることもできないので、処理系は即時関数の実体を完全に消すことができる。
また、即時関数はコンパイル時にしか取得できない情報へアクセスするコンパイラマジックな関数を表現するのにも使用できる。C++20では、ソースコード上の位置を返すstd::source_location::current()
関数が即時関数になっている。
当初は constexpr!
というキーワードが提案されていたが、最終的にconsteval
になった。