web-dev-qa-db-ja.com

constexpr ifおよびstatic_assert

P0292R1 constexpr ifincluded でした。C++ 17の予定です。 SFINAEの使用を置き換えることができます(SFINAEの使用に取って代わることができます)が、static_assertが不正な形式であり、偽ブランチでの診断は不要に関するコメントが怖い:

Disarming static_assert declarations in the non-taken branch of a
constexpr if is not proposed.

void f() {
  if constexpr (false)
    static_assert(false);   // ill-formed
}

template<class T>
void g() {
  if constexpr (false)
    static_assert(false);   // ill-formed; no 
               // diagnostic required for template definition
}

Constexpr if内でstatic_assertを使用することは完全に禁止されていると思います(少なくともfalse /実行されていないブランチですが、実際にはそれは安全でも有用でもないことを意味します)。

これは標準テキストからどのように発生しますか?私は提案文言でstatic_assertについて言及していないことを発見し、C++ 14 constexpr関数はstatic_assertを許可します(cppreferenceの詳細: constexpr )。

この新しい文に隠れていますか(6.4.1以降)? :

Constexpr ifステートメントがテンプレート化されたエンティティに現れると、それを囲むテンプレートまたはジェネリックラムダのインスタンス化中に、破棄されたステートメントはインスタンス化されません。

それ以降、コールグラフの下のsomewherestatic_assertを呼び出す他のconstexpr(テンプレート)関数を呼び出すことも禁止され、診断は不要だと思います。

一番下の行:

私の理解が正しい場合、constexpr ifの使用について(ドキュメントまたはコード検査から)知る必要があるので、それはstatic_assertの安全性と有用性に非常に厳しい制限を課しませんか?私の心配は見当違いですか?

更新:

このコードは警告なしでコンパイルされます(clang head 3.9.0)が、私の理解ではill-formedであり、診断は不要です。有効かどうか

template< typename T>
constexpr void other_library_foo(){
    static_assert(std::is_same<T,int>::value);
}

template<class T>
void g() {
  if constexpr (false)
    other_library_foo<T>(); 
}

int main(){
    g<float>();
    g<int>();
}
29
Johan Lundberg

これは、テンプレート用に確立されたルール、つまりコンパイラがtemplate<class> void f() { return 1; }を診断できるようにするルールについて話している。 [temp.res]/8 新しい変更を太字で表示:

次の場合、プログラムは不正な形式であり、診断は不要です。

  • テンプレートまたはテンプレート内のconstexpr ifステートメント([stmt.if])のサブステートメントに対して有効な特殊化を生成することはできません。テンプレートがインスタンス化されていない、または
  • [...]

条件が非依存でfalseと評価されるstatic_assertを含むテンプレートに対して有効な特殊化を生成できないため、プログラムは不正な形式のNDRです。

少なくとも1つのタイプに対してtrueと評価できる依存条件を持つstatic_assertsは影響を受けません。

24
T.C.

Edit:この自己回答は例とこの質問につながる誤解のより詳細な説明。 T.C.による短い答え厳密に十分です。

提案を読み直し、 現在のドラフト の_static_assert_を読んだ後、私の心配は誤った方向に導かれたと結論付けました。まず、テンプレートdefinitionに重点を置く必要があります。

不正な形式。テンプレート定義に診断は不要

テンプレートがinstantiatedの場合、すべての_static_assert_は期待どおりに起動します。これはおそらく、私が引用した声明とよく一致しています。

...破棄されたステートメントはインスタンス化されません。

これは少しあいまいですが、破棄されたステートメントで発生するtemplatesはインスタンス化されないことを意味すると結論付けます。ただし、他のコードは構文的に有効でなければなりません。したがって、破棄された_if constexpr_句内のstatic_assert(F)、[Fは文字通りまたはconstexpr値のいずれか]は、_static_assert_を含むテンプレートがインスタンス化されると、依然として「噛み付き」ます。または、常に偽であることがわかっている場合は、宣言時に既に(コンパイラの容認では必要ありません)。

例:( live demo

_#include <type_traits>

template< typename T>
constexpr void some_library_foo(){
    static_assert(std::is_same<T,int>::value);
}

template< typename T>
constexpr void other_library_bar(){
    static_assert(std::is_same<T,float>::value);
}

template< typename T>
constexpr void buzz(){
    // This template is ill-formated, (invalid) no diagnostic required,
    // since there are no T which could make it valid. (As also mentioned
    // in the answer by T.C.).
    // That also means that neither of these are required to fire, but
    // clang does (and very likely all compilers for similar cases), at
    // least when buzz is instantiated.
    static_assert(! std::is_same<T,T>::value);
    static_assert(false); // does fire already at declaration
                          // with latest version of clang
}

template<class T, bool IntCase>
void g() {
  if constexpr (IntCase){
    some_library_foo<T>();

    // Both two static asserts will fire even though within if constexpr:
    static_assert(!IntCase) ;  // ill-formated diagnostic required if 
                              // IntCase is true
    static_assert(IntCase) ; // ill-formated diagnostic required if 
                              // IntCase is false

    // However, don't do this:
    static_assert(false) ; // ill-formated, no diagnostic required, 
                           // for the same reasons as with buzz().

  } else {
    other_library_bar<T>();
  }      
}

int main(){
    g<int,true>();
    g<float,false>();

    //g<int,false>(); // ill-formated, diagnostic required
    //g<float,true>(); // ill-formated, diagnostic required
}
_

_static_assert_の標準テキストは非常に短いです。標準では、診断でプログラムを不正な形式にする方法です(@immibisも指摘しているように):

7.6 ...変換後の式の値がtrueの場合、宣言は無効です。それ以外の場合、プログラムは不正な形式であり、結果の診断メッセージ(1.4)には文字列リテラルのテキストが含まれます(提供されている場合)...

8
Johan Lundberg