この質問 を参照してください。 constexpr
変数y
を初期化するために使用されるコア定数式の形式が正しくありません。与えられたものはたくさんあります。
しかし、if
をif 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();
}
}
constexpr
のy
指定子は、破棄されたブランチのチェック方法を変更しているようです。これは意図された動作ですか?
@ max66は親切にも他の実装をチェックしてくれました。彼は、エラーはGCC(7.2.0/Head 8.0.0)とClang(5.0.0/Head 6.0.0)の両方で再現可能であると報告しています。
標準では、if constexpr
の-破棄されたステートメントについてはあまり言及されていません。 [stmt.if]には、これらについて基本的に2つのステートメントがあります。
これらはどちらもあなたの使用には当てはまりません。コンパイラは、初期化の場合、constexpr
について文句を言うのは正しいです。 インスタンス化を利用して失敗する場合は、条件をテンプレートパラメータに依存させる必要があることに注意してください。値がテンプレートパラメータに依存していない場合、失敗は次の場合に発生します。テンプレートは定義済みです。たとえば、このコードはまだ失敗します:
template <typename T>
void f() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1<<x;
}
}
ただし、x
をタイプT
に依存させる場合は、f
がint
でインスタンス化されている場合でも問題ありません。
template <typename T>
void f() {
constexpr T x = -1;
if constexpr (x >= 0){
constexpr int y = 1<<x;
}
}
int main() {
f<int>();
}
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;
}
}
ブランチがチェックされないことを期待する理由がわかりません。 ifブランチが「チェックされていない」場合は、[stmt.if] p2のように、テンプレートの一部であり、インスタンス化ではない場合のみです。
囲んでいるテンプレートエンティティのインスタンス化中に(第17節)、インスタンス化後に条件が値に依存しない場合、破棄されたサブステートメント(存在する場合)はインスタンス化されません。
あなたのコードはこれが当てはまる状況にないようです。