web-dev-qa-db-ja.com

C ++ 17のconstexpr関数でグローバル変数を変更する

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

どのコンパイラが正しいですか?

36
Drew

どのコンパイラが正しいですか?

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 です。


20
Joseph D.

Dcl.constexpr/5に追加で必要なものを追加します。

デフォルトでもテンプレートでもないconstexpr関数またはconstexprコンストラクターの場合、引数値が存在せず、関数またはコンストラクターの呼び出しがコア定数式の評価された部分式になる場合、またはコンストラクターの場合は定数初期化子一部のオブジェクト([basic.start.static])、プログラムは不正な形式であり、診断は不要です。

Foo(true)がコア定数式に評価されるように関数を意図的に作成したため、Foo(false)は必須ではありません。

3
Davislor