📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…
 
(同じ利用者による、間の3版が非表示)
108行目: 108行目:
<br><br>
<br><br>


== 関数のconstexpr ==
== constexpr関数 ==
===== constexpr変数への戻り値の代入 =====
==== constexpr関数の基本 ====
constexprは関数にも付けることができる。<br>
もし、コンパイル時において、関数の引数にconstexpr変数を使用する場合、戻り値でconstexpr変数を初期化する文はコンパイルできる。<br>
関数に付けたconstexprキーワードは、この関数はコンパイル時に計算できることを表している。<br>
もし、コンパイル時において、関数の引数にconstexprでない変数を使用する場合、戻り値でconstexpr変数を初期化する文はコンパイルエラーになる。<br>
<br>
<br>
constexpr変数に入れられる値は、コンパイル時に計算できる値だけである。<br>
constexpr関数の引数にconstexpr変数を与えて、戻り値を使用してconstexpr変数を初期化する文はコンパイルできる。<br>
そのため、constexprキーワードの無い関数の戻り値をconstexpr変数にする時、コンパイラはこの値はコンパイル時には計算できないと考えて、コンパイルエラーを出力する。<br>
それに対し、constexpr関数の引数に実行時に決まる変数を与えて、戻り値を使用してconstexpr変数を初期化するとコンパイルエラーになる。<br>
また、constexprキーワードがある関数の戻り値においても、関数の内容を見て値を計算して、その過程で同様にコンパイル時には計算できない式が1つでもあれば、コンパイルエラーを出力する。<br>
これは、コンパイル時に値を決めることができないからである。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
constexpr int twice(const int n)
{
    return n * 2;
}
constexpr int ten1 = 10;                                    // コンパイル可能
constexpr int ten2 = twice(ten1);                          // コンパイル可能
constexpr int ten3 = twice(static_cast<int>(rand() % 10));  // コンパイルエラー
</syntaxhighlight>
<br>
以下の例では、constexpr関数の引数にconstexprでない変数を与えて、その戻り値でconstexpr変数を初期化しているため、コンパイルエラーになる。<br>
これは、演算結果がROM化できないからである。<br>
それに対し、constexpr関数の引数にconstexprでない変数を与えて、その戻り値でconstexprでない変数を初期化する場合は、コンパイルエラーにならない。<br>
<syntaxhighlight lang="c++">
constexpr int twice(const int n)
{
    return n * 2;
}
int ten = 10;
constexpr int ten2 = twice(ten);  // コンパイルエラー
const int ten3 = twice(ten);      // コンパイル可能
</syntaxhighlight>
<br>
下表に、ROM化できる条件を示す。なお、初期化する変数はconstexpr変数とする。<br>
下表から分かることは以下の3つである。<br>
* 渡す引数の指定子は、<code>const / constexpr</code>を指定する。
* 仮引数の指定子には、<code>指定子なし / const</code>を指定する。
* 関数の指定子は、必ず<code>constexpr</code>を指定する。<br>
<center>
{| class="wikitable"
|-
! 引数の指定子 !! 仮引数の指定子 !!  関数の指定子 !! コンパイルの可否
|- style="text-align:center;"
| × || - || - || ×
|- style="text-align:center;"
| - || - || × || ×
|- style="text-align:center;"
| - || - || const || ×
|- style="text-align:center;"
| - || constexpr || - || ×
|- style="text-align:center;"
| const || × || constexpr || ○
|- style="text-align:center;"
| const || const || constexpr || ○
|- style="text-align:center;"
| constexpr || × || constexpr || ○
|- style="text-align:center;"
| constexpr || const || constexpr || ○
|}
</center>
<br>
上記の例のように、constexpr関数の引数に何を渡すか、constexpr関数の戻り値で何を初期化するかによって、<br>
コンパイル可能またはコンパイルエラーになる。<br>
<br>
これは、設計者に対して、ROM化できるソースコードを記述する促すことになる。<br>
<br>
 
==== constexpr変数への戻り値の代入 ====
constexprは関数にも付加することができる。<br>
関数に付加するconstexprキーワードは、この関数はコンパイル時に計算できることを表している。<br>
<br>
constexpr変数に代入できる値は、コンパイル時に計算できる値だけである。<br>
そのため、constexprキーワードの無い関数の戻り値をconstexpr変数にする場合、<br>
コンパイラはこの値はコンパイル時には計算できないと考えて、コンパイルエラーを出力する。<br>
また、constexprキーワードがある関数の戻り値においても、関数の内容を解析して、<br>
同様に、コンパイル時には計算できない式が1つでもあれば、コンパイルエラーを出力する。<br>
<syntaxhighlight lang="c++">
  #include <iostream>
  #include <iostream>
   
   
147行目: 215行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
また、コンパイル時に計算されているかどうか確認する場合は、<code>static_assert</code>を使用する方法もある。<br>
また、コンパイル時に計算されているかどうか確認する場合は、<code>static_assert</code>を使用する方法もある。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // 常に42を返す関数
  // 常に42を返す関数
  auto answer()
  auto answer()
170行目: 238行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
===== constexprではない引数を与える =====
==== constexprではない引数を与える ====
constexpr関数の結果は、常にコンパイル時に計算されるというわけではない。<br>
constexpr関数の結果は、常にコンパイル時に計算されるというわけではない。<br>
<br>
<br>
179行目: 247行目:
<br>
<br>
constexprキーワードはあくまで「コンパイル時に値が確定できる」ことを伝えるだけで、「コンパイル時にしか値を計算しない」というわけではない。<br>
constexprキーワードはあくまで「コンパイル時に値が確定できる」ことを伝えるだけで、「コンパイル時にしか値を計算しない」というわけではない。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  #include <iostream>
  #include <iostream>
   
   
210行目: 278行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
===== 引数や戻り値のconstとconstexpr関数 =====
==== 引数や戻り値のconstとconstexpr関数 ====
変数のconstexprがconstを兼ねているので見づらいが、関数のconstexprは引数や返り値のconstとは一切関係が無い。<br>
変数のconstexprがconstを兼ねているので見づらいが、関数のconstexprは引数や返り値のconstとは一切関係が無い。<br>
<br>
<br>
以下のサンプルコードでは、answer_constexpr3関数は「変数の参照を受け取り、破壊的変更を加えて、その参照をconstも付けずに返す」という操作を行っているが、<br>
以下のサンプルコードでは、answer_constexpr3関数は「変数の参照を受け取り、破壊的変更を加えて、その参照をconstも付けずに返す」という操作を行っているが、<br>
この操作は全て(少なくともC++14以降では)constexprで行ってよい操作なので、この関数は問題なくconstexpr関数として作ることができる。<br>
この操作は全て(少なくともC++14以降では)constexprで行ってよい操作なので、この関数は問題なくconstexpr関数として作ることができる。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  #include <iostream>
  #include <iostream>
   
   
259行目: 327行目:
     return 0;
     return 0;
  }
  }
</source>
</syntaxhighlight>
<br>
<br>
===== 外部変数の参照 =====
==== 外部変数の参照 ====
constexpr関数で行なってはいけない操作は、主に引数以外のconstexpr以外の外部の変数を参照する操作である。<br>
constexpr関数で行なってはいけない操作は、主に引数以外のconstexpr以外の外部の変数を参照する操作である。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  #include <iostream>
  #include <iostream>
   
   
314行目: 382行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
===== メンバ関数のconstexpr =====
<br>
==== メンバ関数のconstexpr ====
メンバ関数にも<code>constexpr</code>を付けることができる。<br>
メンバ関数にも<code>constexpr</code>を付けることができる。<br>
<code>constexpr</code>を付ける基準は先ほどと同様、「コンパイル時に計算できるかどうか」である。<br>
<code>constexpr</code>を付ける基準は先ほどと同様、「コンパイル時に計算できるかどうか」である。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  class CHoge
  class CHoge
  {
  {
326行目: 395行目:
     auto f(int x, ...) { ... };
     auto f(int x, ...) { ... };
  };
  };
  </source>
  </syntaxhighlight>
を、以下のように考えれば、constexprを付けるかどうかが判断できる。<br>
を、以下のように考えれば、constexprを付けるかどうかが判断できる。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  class CHoge {...};
  class CHoge {...};
  auto f(C& this, int x, ...) { ... };
  auto f(C& this, int x, ...) { ... };
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  #include <iostream>
  #include <iostream>
   
   
383行目: 452行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
===== 分割ファイルとconstexprとインライン =====
==== 分割ファイルとconstexprとインライン ====
constexprが付いている関数は、コンパイル時に計算可能でなければならない。<br>
constexprが付いている関数は、コンパイル時に計算可能でなければならない。<br>
コンパイル時というのはそれぞれの翻訳単位、すなわち、各ファイルをコンパイルしている場合でも関数が計算できなければならないということである。<br>
コンパイル時というのはそれぞれの翻訳単位、すなわち、各ファイルをコンパイルしている場合でも関数が計算できなければならないということである。<br>
394行目: 463行目:
つまり、<code>constexpr</code>が付いている関数は自動的にinline関数として扱われるということになる。<br>
つまり、<code>constexpr</code>が付いている関数は自動的にinline関数として扱われるということになる。<br>
また、<code>constexpr</code>が付いている変数もinline変数として扱われる。<br>
また、<code>constexpr</code>が付いている変数もinline変数として扱われる。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // main.cpp
  // main.cpp
  #include <iostream>
  #include <iostream>
413行目: 482行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // main.h
  // main.h
  class CHoge1
  class CHoge1
436行目: 505行目:
       constexpr int f(int& x);
       constexpr int f(int& x);
  };
  };
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // sub.cpp
  // sub.cpp
  #include "main.h"
  #include "main.h"
455行目: 524行目:
     return x;
     return x;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
 
==== constexprテンプレート関数 ====
===== constexprテンプレート関数 =====
constexprが付いているテンプレート関数の場合、その関数を実体化した時にconstexpr関数として不適格な場合でもコンパイルエラーにはならず、非constexpr関数として扱われる。<br>
constexprが付いているテンプレート関数の場合、その関数を実体化した時にconstexpr関数として不適格な場合でもコンパイルエラーにはならず、非constexpr関数として扱われる。<br>
以下のサンプルコードの場合、print_and_get関数はどのように実体化してもconstexpr関数にはならないが、コンパイルエラーにもならずに、constexprキーワードが無視される。<br>
以下のサンプルコードの場合、print_and_get関数はどのように実体化してもconstexpr関数にはならないが、コンパイルエラーにもならずに、constexprキーワードが無視される。<br>
465行目: 533行目:
<br>
<br>
おそらく、「テンプレートのいくつかの場合はconstexpr、他の場合はconstexprではないような関数を作成したい」という需要があるからだと推測する。<br>
おそらく、「テンプレートのいくつかの場合はconstexpr、他の場合はconstexprではないような関数を作成したい」という需要があるからだと推測する。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  #include <iostream>
  #include <iostream>
   
   
499行目: 567行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
===== constexprが付いているラムダ式 =====
==== constexprが付いているラムダ式 ====
ラムダ式(のoperator())も、関数と同様にconstexprを指定することができる。(指定しなくとも自動的にconstexprが付けてくれる)<br>
ラムダ式(のoperator())も、関数と同様にconstexprを指定することができる。(指定しなくとも自動的にconstexprが付けてくれる)<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  #include <iostream>
  #include <iostream>
   
   
540行目: 608行目:
     return 0;
     return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br><br>
 
== レビュー ==
# constが付加された変数を見つけた場合、その変数はRAMにしか配置できないものか確認する。<br>もし、ROM化できる場合、constexpr指定子に変更できないか考えて指摘する。
# constexprテンプレート関数の内部に、ROM化できない文や関数呼び出しが入っていないか確認する。
# ESCRでは再帰は使用してはいけないので、constexpr関数内において、再帰を使用してはいけない。
# constexpr関数やconstexpr関数テンプレートを見つけた場合、その戻り値で初期化している変数とconstexpr型指定されているかどうか確認する。<br>そうでなければ、constexpr関数やconstexpr関数テンプレートの存在意義がない。
<br>
以下の例は、constexprを付加しても意味の無い例である。<br>
ただし、コンパイルエラーにはならない。<br>
<syntaxhighlight lang="c++">
template <typename T>
constexpr inline static T GetFromCin()
{
    T value;
    cin >> value;
    return value;
}
</syntaxhighlight>
<br><br>
<br><br>


549行目: 636行目:
* constexprを付けることができる関数の幅は広いので使用するべきである。<br>ただし、テンプレート関数をconstexprにするときは注意が必要である。
* constexprを付けることができる関数の幅は広いので使用するべきである。<br>ただし、テンプレート関数をconstexprにするときは注意が必要である。
<br><br>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:C++]]
[[カテゴリ:C++]]