P0292R1 constexpr if は included でした。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ステートメントがテンプレート化されたエンティティに現れると、それを囲むテンプレートまたはジェネリックラムダのインスタンス化中に、破棄されたステートメントはインスタンス化されません。
それ以降、コールグラフの下のsomewhereがstatic_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>();
}
これは、テンプレート用に確立されたルール、つまりコンパイラがtemplate<class> void f() { return 1; }
を診断できるようにするルールについて話している。 [temp.res]/8 新しい変更を太字で表示:
次の場合、プログラムは不正な形式であり、診断は不要です。
- テンプレートまたはテンプレート内の
constexpr if
ステートメント([stmt.if])のサブステートメントに対して有効な特殊化を生成することはできません。テンプレートがインスタンス化されていない、または- [...]
条件が非依存でfalse
と評価されるstatic_assert
を含むテンプレートに対して有効な特殊化を生成できないため、プログラムは不正な形式のNDRです。
少なくとも1つのタイプに対してtrue
と評価できる依存条件を持つstatic_assert
sは影響を受けません。
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)には文字列リテラルのテキストが含まれます(提供されている場合)...