Hatena::ブログ(Diary)

Life like a clown このページをアンテナに追加 RSSフィード Twitter

2009-12-15

静的配列の要素数を取得する構文

Boost 勉強会に行く途中の新幹線で C++TT を読み返していて気付いた話題.引数に配列を取る場合,下記のように配列の先頭ポインタと要素数を指定する形にする事が多いと思います.

template <class T>
void put_element(const T* p, std::size_t n) {
    ...
}

これに対して,引数に STL コンテナを取る場合にはコンテナのみを指定する形になる事が多いので,配列版と SLT コンテナ版でインターフェースが異なると言うケースがしばしば存在します.

しかし,どうやら配列として宣言したもの(new で動的に確保したものではないもの)に関しては,以下のような書き方をする事によって,ユーザに明示的に要素数を指定してもらわなくても関数内で要素数を知ることができるようです.

template <class T, std::size_t N>
void put_element(const T (&ar)[N]) {
    ...
}

これによって,配列と STL コンテナのインターフェースを同じにする事ができるので,これまで何となく気持ち悪かったいくつかの個所を改善できそうです.ただし,上記の定義しかしていない場合は new で確保したような(動的)配列を指定する事ができなくなるので,その点には注意が必要そうですが.

サンプル・コード
#include <iostream>
#include <ostream>
#include <vector>

/* ------------------------------------------------------------------------- */
//  STL コンテナ用の関数
/* ------------------------------------------------------------------------- */
template <class Container>
void put_element(const Container& v) {
    for (typename Container::const_iterator pos = v.begin(); pos != v.end(); ++pos) {
        std::cout << *pos << std::endl;
    }
}

/* ------------------------------------------------------------------------- */
//  静的配列用の関数
/* ------------------------------------------------------------------------- */
template <class T, std::size_t N>
void put_element(const T (&ar)[N]) {
    std::cout << "size: " << N << std::endl;
    for (size_t i = 0; i < N; ++i) {
        std::cout << ar[i] << std::endl;
    }
}

int main() {
    std::vector<int> v;
    v.push_back(10);
    v.push_back(5);
    v.push_back(2);
    put_element(v);
    
    int ar[5];
    ar[0] = 2;
    ar[1] = 4;
    ar[2] = 6;
    ar[3] = 8;
    ar[4] = 10;
    put_element(ar);
    
    int* p = new int[3];
    p[0] = 1;
    p[2] = 2;
    p[3] = 3;
    //put_element(p); // これはエラー
    delete [] p;
    
    return 0;
}