MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C++の基礎 - constexprのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C++の基礎 - constexpr
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == C++には、<code>constexpr</code>という概念がある。<br> <br> * constexprが使用できない、または、使用すべきではない場合 ** 変数 **: constでない変数 **: クラスのメンバ変数 **: 標準入力などの非constexpr関数を使用して計算する値 **: 引数等のconstexprでない可能性がある値を使用して計算する値 **: <br> ** 関数 **: インライン化できない関数 **: 引数でもthisでもない非constexprな外側の変数を参照する操作を含む関数 **: 引数でもthisでもない外側に副作用を及ぼすような操作を含む関数 **: <br> * constexprを使用すべき場合 ** 上記以外全て <br><br> == 変数のconstexpr == 変数におけるconstexprは、<code>#define</code>等で作成するようなコンパイル時定数を作るためのキーワードである。<br> <br> constとは「この変数は変更しないため、変更しようとする場合はコンパイルエラーにする」という合図であるのに対して、<br> constexprとは「この変数の値はコンパイル時に確定するため、確定しない場合はコンパイルエラーにする」という合図である。<br> <br> また、constexpr変数は、const変数としても扱われる。<br> <br> コンパイラは、constexprがついた変数の値をコンパイル時に計算しようとする。もし、計算できなければ、コンパイルエラーを出力する。<br> 以下のサンプルコードでは、"標準入力から受け取る"という操作がコンパイル時に行えないため、コンパイルエラーとなる。<br> <br> どの操作がコンパイル時に計算可能かは、関数にconstexprキーワードが付いているかどうかで判断される。(後述のセクションで記載する)<br> <source lang="c++"> #include <iostream> // 標準入力からint型の値を受け取って返す(コンパイル時に値が定まらない)関数 auto get_value_from_stdin() { int v; std::cin >> v; return v; } int main() { auto a = 1; // 通常の変数 const auto b = 2; // Const constexpr auto c = 3; // Constexpr a = 4; // コンパイル可能 aは後から書き換えてよい // b = 5; // コンパイルエラー bはconstなので書き換えてはいけない // c = 6; // コンパイルエラー cはconstなので書き換えてはいけない std::cout << a << ", " << b << ", " << c << std::endl; auto d = get_value_from_stdin(); // コンパイル可能 dは実行時に受け取った値 const auto e = get_value_from_stdin(); // コンパイル可能 eは実行時に受け取り、今後変更されない値 // constexpr auto f = get_value_from_stdin(); // コンパイルエラー fはコンパイル時に値が確定しなければならない std::cout << d << ", " << e << /* ", " << f << */ std::endl; return 0; } </source> <br><br> == 関数のconstexpr == ===== constexpr変数への戻り値の代入 ===== constexprは関数にも付けることができる。<br> 関数に付けたconstexprキーワードは、この関数はコンパイル時に計算できることを表している。<br> <br> constexpr変数に入れられる値は、コンパイル時に計算できる値だけである。<br> そのため、constexprキーワードの無い関数の戻り値をconstexpr変数にする時、コンパイラはこの値はコンパイル時には計算できないと考えて、コンパイルエラーを出力する。<br> また、constexprキーワードがある関数の戻り値においても、関数の内容を見て値を計算して、その過程で同様にコンパイル時には計算できない式が1つでもあれば、コンパイルエラーを出力する。<br> <source lang="c++"> #include <iostream> // 常に42を返す関数 auto answer() { return 42; } // 常に42を返すconstexprな関数 constexpr auto answer_constexpr() { return 42; } // 常に42を返すconstexprな関数(?) constexpr auto answer_print() { // std::cout << 42 << std::endl; // コンパイルエラー 標準出力への書き出しはコンパイル時には行えない return 42; } int main() { // constexpr auto a = answer(); // コンパイルエラー answer関数はconstexpr関数ではない constexpr auto b = answer_constexpr(); // コンパイル可能 answer_constexpr関数はconstexpr関数 // constexpr auto c = answer_stdin(); // コンパイルエラー answer_stdin関数はコンパイルできない std::cout << /* a << ", " << */ b << /* ", " << c << */ std::endl; return 0; } </source> <br> また、コンパイル時に計算されているかどうか確認する場合は、<code>static_assert</code>を使用する方法もある。<br> <source lang="c++"> // 常に42を返す関数 auto answer() { return 42; } // 常に42を返すconstexprな関数 constexpr auto answer_constexpr() { return 42; } int main() { // static_assert(answer() || true); // コンパイルエラー answer()はコンパイル時に計算できない static_assert(answer_constexpr() || true); // コンパイル可能 answer_constexpr()はconstexpr関数 return 0; } </source> <br> ===== constexprではない引数を与える ===== constexpr関数の結果は、常にコンパイル時に計算されるというわけではない。<br> <br> 以下のサンプルコードでは、constexprが付いているanswer_constexpr関数の引数questionはconstexprではないが、<br> この場合でもコンパイル可能で、answer_constexpr関数はあたかもconstexprキーワードの無い関数のように(少なくとも(1)の行では)動作する。<br> <br> constexprキーワードはあくまで「コンパイル時に値が確定できる」ことを伝えるだけで、「コンパイル時にしか値を計算しない」というわけではない。<br> <source lang="c++"> #include <iostream> // 標準入力から int 型の値を受け取って返す関数 auto get_value_from_stdin() { int v; std::cin >> v; return v; } // 常に42を返すconstexprな関数 constexpr auto answer_constexpr([[maybe_unused]] int question) { return 42; } int main() { constexpr auto value_constexpr = 1; // constexprな値 const auto value_const = get_value_from_stdin(); // constだがconstexprではない値 constexpr auto a = answer_constexpr(value_constexpr); // コンパイル可能 引数がconstexprなので、コンパイル時に値が確定する // constexpr auto b = answer_constexpr(value_const); // コンパイルエラー 引数がconstexprな値ではないので、コンパイル時に値が確定しない const auto c = answer_constexpr(value_constexpr); // コンパイル可能 引数がconstexprなので、コンパイル時に値が確定する const auto d = answer_constexpr(value_const); // (1) コンパイル可能 引数がconstexprな値ではないので、コンパイル時に値は確定しないが、コンパイルエラーにはならない std::cout << a << ", " << /* b << ", " << */ c << ", " << d << std::endl; return 0; } </source> <br> ===== 引数や戻り値のconstとconstexpr関数 ===== 変数のconstexprがconstを兼ねているので見づらいが、関数のconstexprは引数や返り値のconstとは一切関係が無い。<br> <br> 以下のサンプルコードでは、answer_constexpr3関数は「変数の参照を受け取り、破壊的変更を加えて、その参照をconstも付けずに返す」という操作を行っているが、<br> この操作は全て(少なくともC++14以降では)constexprで行ってよい操作なので、この関数は問題なくconstexpr関数として作ることができる。<br> <source lang="c++"> #include <iostream> // OK、常に 42 を返す、 constexpr な関数 constexpr auto answer_constexpr([[maybe_unused]] int question) { return 42; } // OK、常に 42 を返す、 constexpr な関数 constexpr auto answer_constexpr2([[maybe_unused]] const int question) { return 42; } // OK、与えられた引数に 1 を足して返す、 constexpr な関数 // 受け取る変数を直接書き換えて返すので何も const じゃないように見えるが、れっきとした constexpr 関数である constexpr auto& answer_constexpr3(int& question) { question += 1; return question; } // OK、 answer_constexpr3 に直接 constexpr な変数は渡せないが、 // 「const でない変数を渡して constexpr 関数を用いて計算する」こと自体は constexpr constexpr auto use_answer_constexpr3(int question) { auto q = question; q = answer_constexpr3(q); return q; } int main() { constexpr auto value = 41; constexpr auto a = answer_constexpr(value); constexpr auto b = answer_constexpr2(value); constexpr auto c = use_answer_constexpr3(value); std::cout << a << ", " << b << ", " << c << std::endl; return 0; } </source> <br> ===== 外部変数の参照 ===== constexpr関数で行なってはいけない操作は、主に引数以外のconstexpr以外の外部の変数を参照する操作である。<br> <source lang="c++"> #include <iostream> // 標準入力からint型の値を受け取って返す(コンパイル時に値が定まらない)関数 auto get_value_from_stdin() { int v; std::cin >> v; return v; } namespace sample { const auto outer = get_value_from_stdin(); // 外部の変数 constexpr auto outer_constexpr = 42; // constexprな外部の変数 // コンパイルエラー 外部の変数を参照しているのでconstexpr関数にできない // constexpr auto f_outer() // { // return outer; // } // コンパイル可能 constexprな外部の変数は参照してもよい constexpr auto f_outer_constexpr() { return outer_constexpr; } constexpr int& f_argument(int& x) { x += 1; // OK、引数になら色々やってもよい return x; } constexpr auto use_f_argument() { int x = 41; return f_argument(x); } } int main() { // constexpr auto a = sample::f_outer(); // コンパイルエラー f_outerはコンパイルできない constexpr auto b = sample::f_outer_constexpr(); constexpr auto c = sample::use_f_argument(); std::cout << /* a << ", " << */ b << ", " << c << std::endl; return 0; } </source> <br><br> __FORCETOC__ [[カテゴリ:C++]]
C++の基礎 - constexpr
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse