c_array つくった。

すでに誰得感が漂っていますが……。


[ソース]

#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/range/algorithm/equal.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/assert.hpp>
#include <boost/range/irange.hpp>
#include <vector>
#include <iostream>

namespace mpl = boost::mpl;

template<typename Seq, typename ArrayType = array_type<mpl::_1, mpl::_2> >
struct c_array;

int
main(){
    boost::array<int, 4> v = {10, 3, 5, 2};
    BOOST_ASSERT(boost::equal(
        v, c_array<mpl::vector_c<int, 10, 3, 5, 2> >::value
    ));
    
    boost::for_each(
        c_array<mpl::range_c<int, 0, 5> >::value,
        std::cout << boost::lambda::_1 << ","
    );
    std::cout << std::endl;
    
    std::vector<int> v2
        = c_array<mpl::range_c<int, -5, 5>, std::vector<mpl::_1> >::value;
    boost::for_each(
        v2,
        std::cout << boost::lambda::_1 << ","
    );
    
    return 0;
}

[出力]

 0,1,2,3,4,
 -5,-4,-3,-2,-1,0,1,2,3,4,


mpl::c_str の Constant Sequence 版?
mpl::vector_c とかを Boost.Array とかに変換します。

boost::array<int, 4> v = c_array<mpl::vector_c<int, 10, 3, 5, 2> >::value;
BOOST_ASSERT(boost::equal(
    v, c_array<mpl::vector_c<int, 10, 3, 5, 2> >::value
));

c_array と、いいつつ、デフォルトでは、 Boost.Array を使っているので、cpp_array に変えるべきか否か。
生配列は Boost.Array で、こんがり焼きましょう。


また、第二引数に、value_type を渡すことも出来ます。
std::vector を使用するならこんな感じ。

std::vector<int> v2
    = c_array<mpl::range_c<int, -5, 5>, std::vector<mpl::_1> >::value;
BOOST_ASSERT(boost::range::equal(
        v2, boost::irange(-5, 5)
));

mpl::_1 には配列の型が、mpl::_2 には、配列のサイズが渡されます。


配列の初期化は、Boost.Assign を使っています。
一応、BOOST_NO_INITIALIZER_LISTS で、切り替えているので、initializer_list が実装されている場合は、

value = {
    boost::mpl::at_c<Seq, 0>::type::value,
    boost::mpl::at_c<Seq, 1>::type::value,
    boost::mpl::at_c<Seq, 2>::type::value,
    ...
};

な感じで、初期化を行っています。
手元に initializer_list を実装した環境がないので試していませんが……。


あと以前作った、オレオレ Initialized を使えば、クラス内の変数で初期化を行うことが出来ます。

struct hoge{
    typedef c_array<mpl::range_c<int, -5, 5>, std::vector<mpl::_1> > init_array;
    std::vector<int> const& array() const{
        return array_;
    }
private:
    initialized< init_array > array_;    // std::vector<int> array_;
};

hoge h;
BOOST_ASSERT(boost::equal(
    h.array(), boost::irange(-5, 5)
));

やったね!


[boost]

  • ver 1.46.1


実装は以下から。

#include <boost/mpl/size.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/at.hpp>
#include <boost/array.hpp>

#include <boost/preprocessor/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum.hpp>


#ifndef C_ARRAY_LIMIT_SIZE
#    define C_ARRAY_LIMIT_SIZE 100
#endif


#if defined BOOST_NO_INITIALIZER_LISTS
    // initializer_list が実装されていない場合は、Boost.Assign を使用して、初期化を行う
    #include <boost/assign.hpp>
    #define PP_C_ARRAY_AC_C(z, n, text) \
        (boost::mpl::at_c<Seq, n>::type::value)
    
    #define PP_C_ARRYA_AC_C_INITIALIZER(n)    \
        boost::assign::list_of BOOST_PP_REPEAT_FROM_TO(0, n, PP_C_ARRAY_AC_C, _)
#else
    // initializer_list が実装されている場合は、initializer_list を使用する
    #define PP_C_ARRAY_AC_C(z, n, text) \
        boost::mpl::at_c<Seq, n>::type::value
    
    #define PP_C_ARRYA_AC_C_INITIALIZER(n)    \
        { BOOST_PP_ENUM(n, PP_C_ARRAY_AC_C, _)  }
#endif


namespace detail{

template<typename T, typename Size>
struct array_type
    : boost::mpl::identity<boost::array<T, Size::value> >{};

template<
    typename Seq, long Size,
    typename ArrayType
>
struct c_array_impl;

#define PP_C_ARRAY(z, n, text)                              \
template<                                                   \
    typename Seq,                                           \
    typename ArrayType                                      \
>                                                           \
struct c_array_impl<Seq, n, ArrayType>{                     \
    typedef c_array_impl<Seq, n, ArrayType> type;           \
                                                            \
    typedef typename boost::mpl::apply<                     \
        ArrayType,                                          \
        typename Seq::value_type, boost::mpl::size<Seq>     \
    >::type value_type;                                     \
                                                            \
    static value_type const value;                          \
                                                            \
    operator value_type const&() const{                     \
        return value;                                       \
    }                                                       \
};                                                          \
                                                            \
template<typename Seq, typename ArrayType>                  \
typename c_array_impl<Seq, n, ArrayType>::value_type const  \
c_array_impl<Seq, n, ArrayType>::value = PP_C_ARRYA_AC_C_INITIALIZER(n);

BOOST_PP_REPEAT_FROM_TO(1, C_ARRAY_LIMIT_SIZE, PP_C_ARRAY, _)

#undef PP_C_ARRAY
#undef PP_C_ARRAY_AC_C
#undef PP_C_ARRYA_AC_C_INITIALIZER

}  // namespace detail

template<
    typename Seq,
    typename ArrayType = detail::array_type<boost::mpl::_1, boost::mpl::_2>
>
struct c_array
    : detail::c_array_impl<Seq, boost::mpl::size<Seq>::value, ArrayType>{};


#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/range/algorithm/equal.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/assert.hpp>
#include <boost/range/irange.hpp>
#include <vector>
#include <iostream>

namespace mpl = boost::mpl;

int
main(){
    
    boost::array<int, 4> v = {10, 3, 5, 2};
    BOOST_ASSERT(boost::equal(
        v,
        c_array<mpl::vector_c<int, 10, 3, 5, 2> >::value
    ));
    
    boost::for_each(
        c_array<mpl::range_c<int, 0, 5> >::value,
        std::cout << boost::lambda::_1 << ","
    );
    std::cout << std::endl;
    
    std::vector<int> v2
        = c_array<mpl::range_c<int, -5, 5>, std::vector<mpl::_1> >::value;
    boost::for_each(
        v2,
        std::cout << boost::lambda::_1 << ","
    );
    
    return 0;
}