もうconstexprについていく自信がない。現在、文面にバグがあるので議論されている最中だが、どうも、本来の意図する定義では、以下のようなことができるはずである。
constexpr int f() { return 1 ; } constexpr int g() { return 2 ; } constexpr int h() { return 3 ; } constexpr int (*table[])(void) = { &f, &g, &h } ; constexpr int call( int i ) { return table[i]() ; }
これは、ジャンプテーブルをコンパイル時に構築して、コンパイル時に実行するコードである。
また、initializer_listを、constexpr対応させようという意見もある。現在、initializer_listは、constexpr対応ではないが、これをconstexpr対応にしようというのだ。
constexpr int f( std::initializer_list<int> list ) { return *list.begin() ; } int main() { constexpr int value = f( { 1, 2, 3 } ) ; // 1 }
もうついていけそうにない。
Bjarne Stroustrupが恐れていた混沌の領域に達していませんか・・・
ReplyDelete確かにやってやれない事はないけどアホみたいに巨大な言語仕様になりますね。
> 以下のようなことができるはずである。
ReplyDeletetable[i]() で呼び出している関数は constexpr function ではないので、
constexpr function である call() の中からは呼び出せません。
少なくとも現行のドラフトでは「 constexpr function へのポインタ」という
型は存在しません。
constexprはtype specifierではありません。
ReplyDeleteしたがって、constexprは型には影響しません。
また、関数ポインターはリテラル型です。リテラル型は、constexpr指定できます。
定数式では、ポインターを取得するのに、かなりの制限があるというだけです。
constexpr が type specifier であるとは言っているわけではありません。
ReplyDelete(むしろ逆のことを言っているつもりです。)
constexpr は型に影響しないことにより、関数に対する constexpr 修飾が
不可能となる関数ポインタ経由の関数呼び出しは constexpr function に
含めることはできない、という指摘をしています。
constexpr int (*table[])(void) における constexpr は table の宣言に
影響するのであって、それが自動的にポインタの指す先に波及したりは
しません。 static int (*table[])(void) としても table が static になる
だけで、ポインタの指す関数に static が波及するわけではないのと同様です。
関数が constexpr function となる( constexpr function から呼び出せる
関数となる)条件は 7.1.5 p2 にしか見当たりません。
関数呼び出し式のオペランドが、lvalueの関数、ポインター、リファレンス、いずれでも、それは「関数を呼び出す」といえます。
ReplyDelete5.19/2には、定数式となる場合を列挙してありますが、constexprな関数の呼び出しは、引数も定数式などの条件を満たせば、定数式であると書いてあります。どのように呼び出すものが該当するのかということは書いてありません。
つまり、どんな呼び出しであろうと、constexpr関数を参照する定数式のオペランドに対して、定数式の条件を満たして、関数呼び出しの演算子を適用した場合、定数式になります。
そのため、ポインター経由のconstexpr関数の呼び出しも、定数式になりえます。
関数ポインターも定数式であればいいのです。
これは、標準化委員会でも合意が取れている解釈です。
なるほど。 constexpr なテーブルから取り出した
ReplyDelete関数ポインタであれば、それを経由して呼び出す関数も
constexpr なものかどうか、型によらず判別可能という
ことですね。
table[] に constexpr でない関数へのポインタが
混ざっていた場合は、与えるインデックスによっては
コンパイルエラーになる、と。
理解しました。コンパイラ実装者はたいへんになりそう
ですね。
非constexpr関数のポインターは、定数式ではないので、そもそも初期化に失敗します。
ReplyDelete