91

C ++ 0xは、aから.へのいわゆるナローイング変換を必要とするため、次のコードおよび同様のコードを不正な形式します。doubleint

int a[] = { 1.0 };

この種の初期化が実際のコードで多く使用されているのではないかと思います。この変更によっていくつのコードが壊れますか?コードがまったく影響を受けている場合、コードでこれを修正するのは大変な努力ですか?


参考までに、n3225の8.5.4/6を参照してください。

ナローイング変換は暗黙の変換です

  • 浮動小数点型から整数型へ、または
  • long doubleからdoubleまたはfloat、またはdoubleからfloat。ただし、ソースが定数式であり、変換後の実際の値が表現可能な値の範囲内にある場合(正確に表現できない場合でも)、または
  • 整数型またはスコープなし列挙型から浮動小数点型へ。ただし、ソースが定数式であり、変換後の実際の値がターゲット型に適合し、元の型に変換して元の値を生成する場合を除きます。
  • 整数型またはスコープなし列挙型から、元の型のすべての値を表すことができない整数型へ。ただし、ソースが定数式であり、変換後の実際の値がターゲット型に適合し、次の場合に元の値を生成する場合を除きます。元のタイプに変換されます。
4

8 に答える 8

42

GCCを使用したときに、この重大な変更に遭遇しました。コンパイラは、次のようなコードのエラーを出力しました。

void foo(const unsigned long long &i)
{
    unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32};
}

機能中void foo(const long long unsigned int&)

(((long long unsigned int)i) & 4294967295ull)エラー:から内部long long unsigned intへの変換を狭めるunsigned int{}

(((long long unsigned int)i) >> 32)エラー:から内部long long unsigned intへの変換を狭めるunsigned int{}

幸い、エラーメッセージは単純で、修正は簡単でした。

void foo(const unsigned long long &i)
{
    unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF),
            static_cast<unsigned int>(i >> 32)};
}

コードは外部ライブラリにあり、1つのファイルに2つしかありませんでした。重大な変更が多くの​​コードに影響を与えるとは思わない。ただし、初心者は混乱する可能性 あります。

于 2011-01-14T12:25:07.177 に答える
10

過去12年間に書いたC++コードのいずれかにこの種の問題があったことを知って、私は驚き、失望しました。しかし、ほとんどのコンパイラーは、何かが足りない場合を除いて、コンパイル時の「ナローイング」について警告を発していました。

これらもコンバージョンを狭めていますか?

unsigned short b[] = { -1, INT_MAX };

もしそうなら、それらはあなたのフローティングタイプからインテグラルタイプの例よりも少し頻繁に現れるかもしれないと思います。

于 2010-12-13T22:49:13.927 に答える
8

私が遭遇した実際の例:

float x = 4.2; // an input argument
float a[2] = {x-0.5, x+0.5};

数値リテラルは暗黙的doubleに昇格を引き起こします。

于 2012-11-03T19:13:02.353 に答える
7

誰かが次のようなものに巻き込まれたとしても、私はそれほど驚かないでしょう。

float ra[] = {0, CHAR_MAX, SHORT_MAX, INT_MAX, LONG_MAX};

(私の実装では、最後の2つは、int / longに変換して戻したときに同じ結果を生成しないため、狭くなっています)

でも、これを書いたことは覚えていません。限界への近似が何かに役立つ場合にのみ役立ちます。

これも少なくとも漠然ともっともらしいようです:

void some_function(int val1, int val2) {
    float asfloat[] = {val1, val2};    // not in C++0x
    double asdouble[] = {val1, val2};  // not in C++0x
    int asint[] = {val1, val2};        // OK
    // now do something with the arrays
}

しかし、それは完全に説得力があるわけではありません。なぜなら、私が正確に2つの値を持っていることがわかっているのなら、なぜそれらを単にではなく配列に入れるのfloat floatval1 = val1, floatval1 = val2;でしょうか。しかし、なぜそれをコンパイルする必要があるのか​​(そして、精度の低下がプログラムの許容可能な精度の範囲内である場合は機能する)、そうではないのか、動機は何float asfloat[] = {val1, val2};ですか?いずれにせよ、2つのintから2つのfloatを初期化していますが、1つのケースでは、2つのfloatがたまたま集合体のメンバーであるということです。

これは、(特定の実装では)ソースタイプのすべての値がデスティネーションタイプで表現可能であり、元の値に変換可能であるにもかかわらず、非定数式が結果として変換を狭める場合には特に厳しいように思われます。

char i = something();
static_assert(CHAR_BIT == 8);
double ra[] = {i}; // how is this worse than using a constant value?

バグがないと仮定すると、おそらく修正は常に変換を明示的にすることです。マクロで奇妙なことをしているのでない限り、配列初期化子は配列の型の近く、または少なくとも型を表すものの近くにしか表示されないと思います。これはテンプレートパラメーターに依存する可能性があります。したがって、冗長であれば、キャストは簡単なはずです。

于 2010-12-14T01:07:53.290 に答える
6

CFLAGSに-Wno-narrowingを追加してみてください。例:

CFLAGS += -std=c++0x -Wno-narrowing
于 2017-05-20T14:56:13.363 に答える
4

変換エラーを狭めることは、暗黙の整数拡張ルールとうまく相互作用しません。

次のようなコードでエラーが発生しました

struct char_t {
    char a;
}

void function(char c, char d) {
    char_t a = { c+d };
}

これは、ナローイング変換エラーを生成します(これは標準に従って正しいです)。その理由はcd暗黙的にに昇格されint、結果intが初期化子リストのcharに絞り戻されないためです。

OTOH

void function(char c, char d) {
    char a = c+d;
}

もちろんまだ大丈夫です(そうでなければ、すべての地獄が解き放たれます)。しかし、驚くべきことに、

template<char c, char d>
void function() {
    char_t a = { c+d };
}

は問題なく、cとdの合計がCHAR_MAX未満の場合、警告なしでコンパイルされます。これはまだC++11の欠陥だと思いますが、そこにいる人々はそうではないと考えています-おそらく、暗黙の整数変換(人々がコードを書いたときの過去の遺物)を取り除くことなく修正するのは簡単ではないためですchar a=b*c/d(b * c)> CHAR_MAX)または変換エラーの絞り込み(これはおそらく良いことです)でも機能することを期待しています。

于 2012-03-23T10:02:24.140 に答える
3

この機能の実際の経験から、C++03コードベースをC++11に移植する際の実際の苦痛のために、多くの場合、gccがエラーからの警告に狭まったことが示されているため、これは重大な変更でした。gccバグレポートでこのコメントを参照してください:

この規格では、「適合実装は少なくとも1つの診断メッセージを発行する」ことのみを要求しているため、警告付きでプログラムをコンパイルできます。Andrewが言ったように、-Werror = narrowingを使用すると、必要に応じてエラーにすることができます。

G ++ 4.6はエラーを出しましたが、多くの人(私自身を含む)が、大きなC++03コードベースをC++11としてコンパイルしようとしたときに最も一般的に発生する問題の1つである変換を狭めることに気付いたため、意図的に4.7の警告に変更されました。char c [] = {i、0};などの以前は整形式のコード (ここで、私はcharの範囲内にのみ存在します)エラーが発生し、char c [] = {(char)i、0}に変更する必要がありました。

于 2018-12-18T06:00:10.043 に答える
1

GCC-4.7では、変換を絞り込むためのエラーは発生しなくなりましたが、代わりに警告が表示されます。

于 2012-05-29T08:49:58.917 に答える