読者です 読者をやめる 読者になる 読者になる

C++1z コンテナの要素情報にアクセスする非メンバ関数

C++

C++11では、範囲for文を拡張することを目的として、std::begin()std::end()という非メンバ関数が導入されました。

std::vector<T> v;

// 先頭要素を指すイテレータ、終端イテレータを非メンバ関数で取り出す
decltype(v)::iterator first = std::begin(v);
decltype(v)::iterator last = std::end(v);

これらの非メンバ関数は組み込み配列版に対するオーバーロードが用意されていることもあり、範囲for文を拡張する以外の目的でも便利に使われはじめ、C++14では範囲for文とは直接関係のないconst_iterator版のstd::cbegin()std::cend()、reverse_iterator版のstd::rbegin()std::rend()などが導入されました。

C++1zでは、組み込み配列とコンテナを共通インタフェースで扱えることなどを目的として、以下の非メンバ関数が導入されます:

  • std::empty() : コンテナが空か判定する
  • std::size() : コンテナの要素数を取得する
  • std::data() : コンテナの生データ(ポインタ)を取得する

これらのうち、std::size()はとくに組み込み配列の要素数を取得するために、便利に使えるでしょう。

#include <iterator>
#include <cstddef>

int main()
{
    int ar[] = {3, 1, 4};
    constexpr std::size_t size = std::size(ar);
    static_assert(size == 3);
}

この関数を使えば、#define ARRAYSIZE(a) (sizeof(a)/sizeof(*(a)))のようなマクロは必要なくなります。

その他の要点は、以下の通りです:

  • これらの関数は、<iterator>ヘッダで定義される
  • これらの関数は、constexpr関数として定義される
  • これらの関数のうちコンテナ版は、戻り値の型がコンテナの定義に依存する
    • たとえば、std::empty(c)は直接bool型を返すよう定義されているのではなく、c.empty()の戻り値の型を返すように定義される
  • これらの関数は、関数テンプレートのコンテナ版、std::initializer_list版、組み込み配列版のオーバーロードが標準ライブラリで定義される
  • これらの関数のうちstd::data()だけは、const左辺値参照版と非const左辺値参照版のオーバーロードが定義される。それ以外はconst左辺値参照版のみで、右辺値参照版はない。

宣言

// <iterator>
namespace std {
    // 24.8, container access:
    template <class C> constexpr auto size(const C& c) -> decltype(c.size());
    template <class T, size_t N> constexpr size_t size(const T (&array)[N]) noexcept;
    template <class C> constexpr auto empty(const C& c) -> decltype(c.empty());
    template <class T, size_t N> constexpr bool empty(const T (&array)[N]) noexcept;
    template <class E> constexpr bool empty(initializer_list<E> il) noexcept;
    template <class C> constexpr auto data(C& c) -> decltype(c.data());
    template <class C> constexpr auto data(const C& c) -> decltype(c.data());
    template <class T, size_t N> constexpr T* data(T (&array)[N]) noexcept;
    template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
}

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。