web-dev-qa-db-ja.com

if constexprによってこのコア定数式エラーが消えないのはなぜですか?

この質問 を参照してください。 constexpr変数yを初期化するために使用されるコア定数式の形式が正しくありません。与えられたものはたくさんあります。

しかし、ifif constexprに変えようとすると:

template <typename T>
void foo() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1 << x;
    }
}

int main(){
    foo<int>();
}

エラーが続く。 GCC 7.2がまだ提供している場合:

error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]

しかし、破棄されたブランチではセマンティックチェックを実行しないでおく必要があると思いました。

ただし、constexprラムダを介して間接化を行うと役立ちます。

template <typename T>
void foo(){
    constexpr int x = -1;
    constexpr auto p = []() constexpr { return x; };
    if constexpr (x >= 0){
        constexpr int y = 1<<p();
    }
}

constexpry指定子は、破棄されたブランチのチェック方法を変更しているようです。これは意図された動作ですか?


@ max66は親切にも他の実装をチェックしてくれました。彼は、エラーはGCC(7.2.0/Head 8.0.0)とClang(5.0.0/Head 6.0.0)の両方で再現可能であると報告しています。

標準では、if constexprの-​​破棄されたステートメントについてはあまり言及されていません。 [stmt.if]には、これらについて基本的に2つのステートメントがあります。

  1. 同封のテンプレートでは、破棄されたステートメントはインスタンス化されません。
  2. 破棄されたステートメントから参照される名前は、ODRを定義する必要はありません。

これらはどちらもあなたの使用には当てはまりません。コンパイラは、初期化の場合、constexprについて文句を言うのは正しいです。 インスタンス化を利用して失敗する場合は、条件をテンプレートパラメータに依存させる必要があることに注意してください。値がテンプレートパラメータに依存していない場合、失敗は次の場合に発生します。テンプレートは定義済みです。たとえば、このコードはまだ失敗します:

template <typename T>
void f() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1<<x;
    }
}

ただし、xをタイプTに依存させる場合は、fintでインスタンス化されている場合でも問題ありません。

template <typename T>
void f() {
    constexpr T x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1<<x;
    }
}
int main() {
    f<int>();
}
20
Dietmar Kühl

Constexpr If によって破棄されたステートメントの場合:

破棄されたステートメントは、考えられるすべての特殊化に対して不正な形式にすることはできません。

この問題を修正するには、テンプレートパラメータに応じてステートメントを作成できます。

template<typename T, int X> struct dependent_value { constexpr static int V = X; };

template <typename T>
void foo() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1 << dependent_value<T, x>::V;
    }
}

[〜#〜]ライブ[〜#〜]

11
songyuanyao

ブランチがチェックされないことを期待する理由がわかりません。 ifブランチが「チェックされていない」場合は、[stmt.if] p2のように、テンプレートの一部であり、インスタンス化ではない場合のみです。

囲んでいるテンプレートエンティティのインスタンス化中に(第17節)、インスタンス化後に条件が値に依存しない場合、破棄されたサブステートメント(存在する場合)はインスタンス化されません。

あなたのコードはこれが当てはまる状況にないようです。

6
Kerrek SB