2015-12-21 10 views
15

最初の断片は、任意の警告(live example)なしでコンパイル:これらのスニペットはGCCによって異なって扱われるのはなぜですか?

#include <iostream> 

struct A { 
    constexpr A(): i(5){} 
    constexpr operator int() { return 5; } 
    int i; 
}; 

int main() { 
    A a; 
    int b[a]{ 0, 1, 2, 3, 4 }; 
    std::cout << b[4] << '\n'; 
} 

今変換演算子(live example)でiを返すことによって、上記のコードを変更:

constexpr operator int() { return i; } 

GCCはbがVLAあることを警告します。

私にとって、両方の変種は、C++の段落§5.19[expr.const]/3に準拠しているようです。

答えて

17

あなたはiのLTR変換を行っているが、[expr.const] /ここに違反することはない(2.7)、(2.7.3)のためには適用されなければなりません:

enter image description here

(2.7.1)は文字列リテラルに関する(2.7.2)の話、(2.7.4)式の評価内で生涯が始まったオブジェクトに関するものです。aの宣言がbの前にあるため適用できません。

aconstexprと定義し、コードは準拠しています。


標準の言う明確に少し補遺:変換

として[expr.const]/4で定義されている括弧内の式は、タイプstd::size_t[dcl.array]/1)の変換定数式でなければなりません、
Tの定数式は、式 Tに暗黙的に変換されます。変換された 式は定数式であり、満たされています。

はこのように、実際に、標準では有効になり

constexpr std::size_t s = a; 

かどうかに興味があります。前述の理由から、以前に定義された非constexprオブジェクトのサブオブジェクトを使用しようとしています。

+0

この場合、 'a'は左辺値と右辺値の変換を行わなければならないのはなぜですか?これは、§5.19/ 3(N4140)の ''変換定数式 'の定義が宣言 'int b [a] {0,1 、2,3,4}; – Ayrosa

+0

@Ayrosaさて、 'a'は一度も実行する必要はありませんが、' std :: size_t'に変換するためには変換演算子を呼び出す必要があります。 ( 'a'は角括弧の中に' std :: size_t'型の定数式を変換したものです) – Columbo

+1

あなたの答えで強調したことを本当に理解するのに時間がかかりました。間違いなく、スタンダードを完全に理解することは容易なことではありません。素晴らしい答え(+1)。 – Ayrosa

4

配列サイズはコンパイル時定数でなければなりませんが、2番目の例ではA::iの初期化は実行時まで行われません。

+0

':: A()'は 'constexpr'ですが... – YSC

+0

@YSCはい、しかし、' main'関数の変数 'a'はそうではありません。 –

+1

そして*これは本当の警告源ですね。 – YSC

関連する問題