24

次の C++11 コードを検討してください。

#include <iostream>

struct X
{
    X(bool arg) { std::cout << arg << '\n'; }
};

int main() 
{
    double d = 7.0;
    X x{d};
}

の初期化で double から bool への縮小変換がありますx。標準に関する私の理解によれば、これは不正なコードであり、何らかの診断が必要です。

Visual C++ 2013 で次のエラーが発生します。

error C2398: Element '1': conversion from 'double' to 'bool' requires a narrowing conversion

ただし、Clang 3.5.0 と GCC 4.9.1 の両方で、次のオプションを使用します。

-Wall -Wextra -std=c++11 -pedantic 

エラーや警告なしでこのコードをコンパイルしてください。プログラムを実行すると、1(驚くことではありません) が出力されます。


では、さらに奇妙な領域に足を踏み入れてみましょう。

に変更X(bool arg)するX(int arg)と、突然、Clang からエラーが発生しました

error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]

そしてGCCからの警告

warning: narrowing conversion of 'd' from 'double' to 'int' inside { } [-Wnarrowing]

これは私が期待していたもののように見えます。


ここで、boolコンストラクターの引数を保持し (つまり、 に戻してX(bool arg))、 に変更double d = 7.0;int d = 7;ます。繰り返しますが、Clang からの縮小エラーですが、GCC は診断をまったく発行せず、コードをコンパイルします。

定数をコンストラクターに直接渡すと得られる動作のバリエーションがいくつかありますが、奇妙なものもあれば、予想されるものもありますが、ここではそれらをリストしません。この質問は長くなりすぎています。


これは、標準準拠に関して VC++ が正しく、Clang と GCC が間違っているというまれなケースの 1 つだと思いますが、これらのコンパイラのそれぞれの実績を考えると、私はまだこれについて非常に躊躇しています。

専門家はどう思いますか?


標準参照 (C++11 の最終標準ドキュメント、ISO/IEC 14882-2011 からの引用):

8.5.4 [dcl.init.list] パラグラフ 3 には、次のものがあります。

— それ以外の場合、T がクラス型の場合、コンストラクターが考慮されます。適用可能なコンストラクターが列挙され、オーバーロード解決 (13.3、13.3.1.7) によって最適なコンストラクターが選択されます。引数のいずれかを変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。

同じセクションのパラグラフ 7 には、次のようなものがあります。

縮小変換は、
浮動小数点型から整数型へ、または
long double から double または float へ、または double から float への暗黙的な変換です。ただし、ソースが定数式で、変換後の実際の値が次の場合を除きます。表現できる値の範囲内 (正確に表現できない場合でも)、または
— ソースが定数式であり、変換後の実際の値である場合を除き、整数型またはスコープなし列挙型から浮動小数点型へターゲット型に適合し、元の型に変換されたときに元の値を生成する、または
— ソースが定数式であり、変換後の実際の値がターゲットの型に適合し、元の値を生成する場合を除き、整数型またはスコープなし列挙型から、元の型のすべての値を表すことができない整数型へ元の型に戻すと。
[注: 上で示したように、そのような変換はリストの初期化の最上位では許可されていません。—注の最後]

3.9.1 [basic.fundamental] パラグラフ 7 には、次のものがあります。

型 bool、char、char16_t、char32_t、wchar_t、および符号付きおよび符号なしの整数型をまとめて整数型と呼びます。48 整数型の同義語は整数型です。

(私はこの段階ですべてに疑問を持ち始めていました...)

4

1 に答える 1

16

次のことを試してみると、これは単にバグのように見えます。

bool b {3} ;

両方gccclang診断を発行します。たとえば、次のようにgcc言います。

警告: { } 内で 'int' から 'bool' への '3' の変換を縮小しています [-Wnarrowing]

これは、C++ 11 標準の草案の8.5.4 リスト初期化パラグラフ7で次のように説明されています。

縮小変換は暗黙の変換です

[...]

  • ソースが定数式であり、変換後の実際の値がターゲットの型に適合し、元の値を生成する場合を除き、整数型またはスコープなし列挙型から元の型のすべての値を表すことができない整数型へ元の型に戻しました。

これは、あなたの例と次のより簡単な例をカバーする同じ段落です:

bool a {3.0} ;

これは、7上で引用した段落の次の箇条書きでカバーされます。

  • 浮動小数点型から整数型へ、または

段落から3、これは形式が正しくなく、診断が必要です:

型 T のオブジェクトまたは参照のリスト初期化は、次のように定義されます。

[...]

  • それ以外の場合、イニシャライザ リストに単一の要素がある場合、オブジェクトまたは参照はその要素から初期化されます。要素を T に変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。

gcc診断は生成されませんがclang、次の警告が表示されますが、表示される縮小変換の警告は表示されません。

警告: 'double' から 'bool' への暗黙的な変換により、値が 3 から true に変更されます [-Wliteral-conversion]

注、セクション3.9.1 [basic.fundamental]には次のように記載されています。

bool、 char 、 char16_t 、 char32_t 、 wchar_t 、および符号付きおよび符号なしの整数型は、まとめて整数型と呼ばれます.48整数型の同義語は整数型です.

clanggccの両方でバグ レポートを提出する必要があります。

Jonathan Wakely は、EDG コンパイラが OP コードの縮小エラーを出すことに注目しています。

アップデート

gccclangのバグ レポートを提出しました。

clang バグ レポートが修正済みとして更新されました。

r229792 で修正されました。

gcc バグ レポートが修正済みとして更新されました。

修理済み。

実際の例はこれを確認しているようです。

于 2014-12-16T15:52:52.727 に答える