3

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

#include <iostream>

int main()
{
    int i{10.1}; // narrowing, should not compile
    std::cout << i << std::endl;
}

C++11 標準によれば、コンパイルすべきではありません (ブレースの初期化でのナローイングは禁止されています)。

現在、コンパイルするとg++4.9.2 -std=c++11警告のみが出力されます

warning: narrowing conversion of '1.01e+1' from 'double' to 'int' inside { } [-Wnarrowing]

フラグを削除する-std=c++11と、ブレースの初期化に関する警告が表示されますが、縮小は行われません。

warning: extended initializer lists only available with -std=c++11 or -std=gnu++11

一方、 g++5はコンパイルしませg++5 -std=c++11. ただし、-std=c++11が省略されている場合でも、g++5喜んでコンパイルし、ナローイングではなく、ブレースの初期化に関連する警告のみを表示します。

warning: extended initializer lists only available with -std=c++11 or -std=gnu++11

上記の振る舞いはバグがあるようでg++4.9、コードをコンパイルすべきではありませg++5-std=c++11。これは既知の問題ですか?

4

3 に答える 3

9

{}内部の縮小変換が C++11 モードでのみエラーになる理由は単純です: C++03 ではエラーではありません。これT var{value};は新しい C++11 構文ですが、T var = {value};すでに有効な C++03 構文であり、縮小変換が可能でした。

int i = { 10.1 }; // valid C++03, invalid C++11

T var{value};これにより、GCC 開発者は、縮小変換を初期化と同じように扱うことが容易になりT var={value};ます。これは、コンパイラでの警告に対して 2 つの別個のコード パスを回避できるため便利です。

これにより、GCC 開発者が C++03 モードの構文を受け入れやすくなり、T var{value};警告するだけです。C++03 モードでは、他のいくつかの C++11 構文拡張も有効になっています。これは、GCC の標準ライブラリの実装でいくつかの C++11 構文拡張が使用されているため (それに関する警告が抑制されているため) 便利です。

int i{10.1}; C++11 モードの GCC 4.9 ではエラーにならず、GCC 5 でエラーになった理由は、それをエラーとして扱わないと、有効なコードが拒否されたためです。C++ 標準では、SFINAE コンテキストでこれをエラーとして扱う必要があります。GCC 4.9 では、これが原因で正しく実行されない有効な C++11 プログラムを次に示します。

#include <stdio.h>
template <typename T> void f(double) { puts("ok"); }
template <typename T, typename = decltype(T{10.1})> void f(int) { puts("error"); }
int main() { f<int>(1); }

これは「ok」を出力するはずです。2 番目のオーバーロードは破棄されることになっています。

GCC 4.9 では、2 番目のオーバーロードが破棄されないため、「エラー」が出力されintますdouble

于 2015-02-11T23:25:02.213 に答える
6

標準では、「コンパイルしてはならない」ということは決してありません ( を除く#error)。特定の不正なプログラムは診断を発行する必要があり、警告を発行することでそれが満たされます。

スイッチを使用して、gcc がすべての診断でコンパイルを停止するようにすることができます-Werror。特定の警告に絞り込むことができます-Werror=narrowing

GNU++ でコンパイルしている場合、または C++11 の代わりにデフォルト モードが何であれ、コンパイラは、問題なく縮小変換を受け入れることを含め、好きなことを行うことができます。

参照: N3936 [intro.compliance]/2

  • プログラムに診断可能なルールの違反が含まれている場合 [...]、適合する実装は少なくとも 1 つの診断メッセージを発行する必要があります。

  • プログラムに診断が不要な規則違反が含まれる場合、この国際規格はそのプログラムに関する実装に要件を課しません。

[defns.diagnostic]

診断メッセージ

実装の出力メッセージの実装定義のサブセットに属するメッセージ

また、最初の箇条書きから、メッセージの数または内容が違反の数または内容に対応している必要はないことに注意してください。

標準では、エラーや警告をどのように整理するかはコンパイラに完全に委ねられていますが、特定の違反についてはそれを黙って無視することはできません。

于 2015-02-11T23:00:44.873 に答える
2

からの引用1.4 [intro.compliance]

適合する実装には、整形式プログラムの動作を変更しないという条件で、拡張機能 (追加のライブラリ関数を含む) が含まれる場合があります。実装は、この国際標準に従って不適切な形式の拡張機能を使用するプログラムを診断する必要があります。ただし、そうしたプログラムをコンパイルして実行することはできます。

初期化の例に該当するセクションは です8.5.4 [dcl.init.list]。特に、

それ以外の場合、初期化子リストに型Eの単一の要素があり、Tが参照型ではないか、その参照型がEに関連する参照である場合、オブジェクトまたは参照はその要素から初期化されます。要素をTに変換するために縮小変換 (以下を参照) が必要な場合、プログラムはill-formedです。

例を添えて

int x1 {2}; // OK
int x2 {2.0}; // error: narrowing

診断の正確な性質は実装によって指定されるため、観察される動作の両方のセットは標準に準拠しています。

于 2015-02-11T23:17:37.560 に答える