web-dev-qa-db-ja.com

`std :: initializer_list`がリテラル型として定義されていないのはなぜですか?

これは、この質問のフォローアップです: constexpr initializer_listオブジェクトを宣言することは合法ですか?

C++ 14以降、std::initializer_listクラスのすべてのメソッドはconstexprでマークされています。 constexpr std::initializer_list<int> list = {1, 2, 3};を実行してインスタンスを初期化できるのは自然なことのようですが、Clang 3.5は、定数式によってlistが初期化されていないことについて文句を言います。 dypがコメントで指摘しているようにstd::initializer_listがリテラル型であるという要件は仕様から消​​えたようです。

クラスをそのように初期化することさえできない場合、クラスをconstexprとして完全に定義することの意味は何ですか?それは規格の見落としであり、将来修正される予定ですか?

60
ChristopherC

標準委員会は、initializer_listがリテラル型であることを意図しているようです。ただし、これは明示的な要件ではないようであり、標準のバグのようです。

§3.9.10.5から:

次の場合、型はリテラル型です。
-次のすべてのプロパティを持つクラスタイプ(第9節):
-それは些細なデストラクタを持っています、
-集約型(8.5.1)であるか、少なくとも1つのconstexprコンストラクターまたはコピーではないコンストラクターテンプレートがありますまたはコンストラクターを移動し、
-その非静的データメンバーと基本クラスはすべて、不揮発性リテラルタイプです。

§18.9.1から:

namespace std {
  template<class E> class initializer_list {
  public:
    /* code removed */
    constexpr initializer_list() noexcept;
    // No destructor given, so trivial
    /* code removed */
  };
}

これは、1番目と2番目の要件を満たします。

ただし、3番目の要件については:

§18.9.2から(私の強調):

タイプinitializer_list<E>のオブジェクトは、タイプconst Eのオブジェクトの配列へのアクセスを提供します。 [注:ポインターのペアまたはポインターと長さinitializer_listの明白な表現になります。 initializer_listは、8.5.4で指定されている初期化リストを実装するために使用されます。初期化子リストをコピーしても、基になる要素はコピーされません。
-エンドノート]

したがって、initializer_listの実装のプライベートメンバーが不揮発性リテラルタイプである必要はありません。ただし、ポインタのペアまたはポインタと長さが「明白な表現」であると彼らが信じているため、おそらく誰かがinitializer_listのメンバーに非リテラルのものを入れる可能性があるとは考えていませんでした。

おそらく、clangと標準の両方のバグだと思います。

5