21
#include <iostream>

struct X {
    X(std::initializer_list<int> list) { std::cout << "list" << std::endl; }
    X(float f) { std::cout << "float" << std::endl; }
};

int main() {
    int x { 1.0f };
    X a(1);     // float (implicit conversion)
    X b{1};     // list
    X c(1.0f);  // float
    X d{1.0f};  // list (narrowing conversion) ARG!!!

    // warning: narrowing conversion of '1.0e+0f' from 'float' to 'int'
    // inside { } [-Wnarrowing]
}

std::initializer_list() 初期化を使用する代わりに、オーバーロード リストから削除する (つまり、非リスト ctor をより有利にする)他の方法はありますか?

GCC 4.8 を使用する http://coliru.stacked-crooked.com/ コンパイラを使用していました

4

4 に答える 4

20

実際、中括弧リスト初期化子に縮小変換を含むプログラムはill-formedです。コンパイラが警告を表示する理由はわかりませんが、ここで間違いなくエラーが発生するはずです (FWIW、Clang はそれを行います)。

また、これも縮小 (したがって不正な) 変換であることに注意してください。

int x { 1.0f }; // ERROR! Narrowing conversion required

C++11 標準のパラグラフ 8.5.4/3 によると:

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

Tが集合体の場合、集合体の初期化が実行されます (8.5.1)。[...]

— それ以外の場合、イニシャライザ リストに要素がない場合 [...]

— それ以外の場合、Tが の特殊化であるstd::initializer_list<E>場合 [...]

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

より正確に言えば、標準では、この場合「診断」が必要であり、警告は診断であ​​るとのみ述べているため、コンパイラの動作は準拠していますが、エラーを発生させる方がより良い動作になると思います。

于 2013-06-05T12:18:47.937 に答える
0

-Wno-c++11-narrowingエラーをオフにするために使用できます。

サンプルのテスト プログラムは次のとおりです。

#include <cstdint>

struct foo {
    int32_t a;
};

void foo(int64_t val) {
    struct foo A = { val };
}

だけで clang++-3.8 でコンパイルすると-std=c++11、次のエラーが表示されます。

ここに画像の説明を入力

追加-Wno-c++11-narrowing、黄金の沈黙:-)

ここに画像の説明を入力

もちろん、狭小化の問題は後で再発する可能性がありますが、技術的負債の痛みを後回しにする方が簡単な場合もあります. ymmv :-)

于 2016-11-26T23:17:14.627 に答える