C++ 17では、constexpr
関数のグローバル変数を変更できますか?
#include <iostream>
int global = 0;
constexpr int Foo(bool arg) {
if (arg) {
return 1;
}
return global++;
}
int main() {
std::cout << global;
Foo(true);
std::cout << global;
Foo(false);
std::cout << global;
}
私はあなたができるとは思わないでしょうが、clang 6はそれを許します: https://godbolt.org/g/UB8iK2
ただし、GCCにはありません: https://godbolt.org/g/ykAJMA
どのコンパイラが正しいですか?
どのコンパイラが正しいですか?
Clangは正しい。
dcl.constexpr/ によるconstexpr
関数の定義
constexpr
関数の定義は、次の要件を満たす必要があります。
(3.1)戻り値の型はリテラル型でなければなりません。
(3.2)各パラメーター型はリテラル型でなければなりません。
(3.3)その関数本体は_= delete
_、_= default
_、またはnot含む:
(3.3.1)asm-definition、
(3.3.2)gotoステートメント、
(3.3.3)識別子ラベル、
(3.3.4)トライブロック、または
(3.3.5)非リテラル型の変数またはstaticまたはスレッドストレージのdefinition期間または初期化が実行されない期間。
また dcl.constexpr/5 に従って:
既定値でもテンプレートでもない
constexpr
関数またはconstexprコンストラクターの場合、引数値が存在しない場合、関数またはコンストラクターの呼び出しは、コア定数式の評価された部分式、
Foo(true)
はcore constant expression(つまり_1
_)に評価できます。
また、Foo(false)
にはを指定できますが、定数を評価する必要はありません。
[〜#〜]結論[〜#〜]
したがって、GCCでは bug です。
Dcl.constexpr/5に追加で必要なものを追加します。
デフォルトでもテンプレートでもないconstexpr関数またはconstexprコンストラクターの場合、引数値が存在せず、関数またはコンストラクターの呼び出しがコア定数式の評価された部分式になる場合、またはコンストラクターの場合は定数初期化子一部のオブジェクト([basic.start.static])、プログラムは不正な形式であり、診断は不要です。
Foo(true)
がコア定数式に評価されるように関数を意図的に作成したため、Foo(false)
は必須ではありません。