23

の要素std::initializer_listが常にconst値である場合、なぜではbegin()/end()なくのようなテンプレートメソッドがあるのcbegin()/cend()ですか?この名前(慣例により、egと比較して)は、両方のメソッドが常に。を返す​​場合に、両方のメソッドがを返す可能std::vector性があることを示唆している可能性があります。std::initializer_listiteratorconst_iterator

4

1 に答える 1

26

に加えてのインターフェイスの一部ではないcbegin()理由についての洞察を提供することはできませんが、最後の2つのメンバー関数がそこにあるべきである理由は確かにあります。cend()std::initializer_list begin()end()

1つの理由は、たとえば、範囲ベースのループが関数と(段落6.5.4 / 1)forの観点からC++11標準によって正確に定義されていることです。したがって、初期化子リストで使用できるようにするには、およびメンバー関数を提供する必要があります。begin()end()std::initializer_listbegin()end()

#include <utility>
#include <iostream>

int main()
{
    auto l = { 1, 2, 3, 4, 5 };
    for (int x : l) // Works because std::initializer_list provides
                    // the member functions begin() and end().
    {
        std::cout << x << " ";
    }
}

さらに、メンバー関数はC ++ 11より前には存在cbegin()していなかったと考えるのは理にかなっています。したがって、のインターフェイスを使用すると、初期化リストに関して記述された古い汎用アルゴリズムを作成し、初期化リストを使用する必要がなくなります。書き直しました。cend()begin()end()std::initializer_listbegin()end()

あなたが書く:

これらの名前(慣例により、egと比較して)は、常に。を返す​​場合、std::vector両方のstd::initializer_listメソッドがを返す可能性があることを示唆している可能性があります。iteratorconst_iterator

実際、このアナロジーはあまり適切ではありません。std::vectorたとえば、の関数は、の非インスタンス(つまり、要素を変更、追加、および削除できる可変のインスタンス)で呼び出されたときと、インスタンス(つまり、コンテンツが不変のインスタンス)で呼び出されbegin()たときを返します。変更できません):iteratorconststd::vectorconst_iteratorconst

#include <vector>
#include <type_traits>

int main()
{
    // A non-const vector...
    std::vector<int> v = { 1, 2, 3, 4, 5 };

    auto i = v.begin();
    static_assert(
        std::is_same<decltype(i), decltype(v)::iterator>::value, 
        //                                     ^^^^^^^^
        //                                     ...non-const iterator!
        "What?");

    // A const vector...
    std::vector<int> const vc = { 1, 2, 3, 4, 5 };
    auto ic = vc.begin();
    static_assert(
        std::is_same<decltype(ic), decltype(vc)::const_iterator>::value,
        //                                       ^^^^^^^^^^^^^^
        //                                       ...const iterator!
        "What?");
}

イニシャライザリストは、定義上、不変のコレクションです。C++11規格のパラグラフ18.9/2による:

タイプのオブジェクトは、タイプinitializer_list<E>のオブジェクトの配列へのアクセスを提供しますconst E。[...]

初期化子リストはconst要素のコレクションであるため、cbegin()およびcend()関数は実際にはとまったく同じことを実行begin()end()ます。

実際、iteratorconst_iteratorは両方とも初期化子リストの値型の定数要素へのポインターとして定義されているので、それが常に返されるのか(あなたが想定しているように)、または常に返されるのかは議論の余地がbegin()あります。end()const_iteratoriterator

これは、C++11標準の段落18.9/1がinitializer_listクラステンプレートを定義する方法です。

namespace std {
    template<class E> class initializer_list {
    public:
        typedef E value_type;
        // ...
        typedef const E* iterator;
        typedef const E* const_iterator;
        // ...
        constexpr const E* begin() const noexcept; // first element
        constexpr const E* end() const noexcept; // one past the last element
    };

    // ...
}
于 2013-03-25T20:10:59.410 に答える