週に一回は書きますよ 月に4つ記事を書けばノルマは満たされます。
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

前回の話: C++で多次元のvectorを多次元の配列で初期化したいのですが、どうしたらマクロを使わずにできるでしょう。

リンク先のように書けばうまく動きました。これでboost::mplも、マクロも書かなくてすみます。助かりました。

スポンサーサイト

目標. 次のようなものをつくる。

int kArray[3][2] = {{1,2}, {4, 5}, {6, 7}};
vector<vector<int> > a(array2Vector(kArray));

配列を渡してvectorに変換する関数です。コンテナのテストに必須です。多次元配列を扱う必要があります。

まず、次のようなことはできません。配列を渡してもまったく処理してくれません。

  • 追記(2009.11.29 20:00): このコードは返り値が間違ってます。これだとint[2][3]がvectorに変換されてしまいます。正しいコードは解答編に。
template<typename T_, int SIZE_>
std::vector<T_> generateVector(T_ array[SIZE_]) {
  std::vector<T_> res;
  for (int i = 0; i < SIZE_; ++i)
    res.push_back(generateVector(array[i]));
  return res;
}
int generateVector(int i) {return i;}

次にboost::mplを使用して、サイズを事前にわたすようにしました。大幅な妥協です。for文を書いて初期化するよりはましです。

template <typename T_, typename B_, typename E_>
class VUVectorInitializerInternal_;

template <typename T_>
class VUIdentity_ {
public:
  typedef T_ result_type;
  typedef T_ parameter_type;
  template <typename U_>
  T_ initialize(U_ rhs) { return rhs;}
};

template <typename T_, typename NC_, typename B_, typename E_>
class VUExpand_ {
public:
  enum { size = NC_::value };
  typedef VUVectorInitializerInternal_<T_, B_, E_> child_type;
  typedef std::vector<typename child_type::result_type> result_type;
  typedef typename child_type::result_type parameter_type[size];
  result_type initialize(parameter_type rhs) {
    result_type result;
    result.reserve(size);
    child_type child;
    for (int i = 0; i < size; ++i)
      result.push_back(child.initialize(rhs[i]));
    return result;
  }
};

template <typename T_, typename B_, typename E_>
class VUVectorInitializerInternal_ :
  public boost::mpl::if_<typename boost::is_same<B_, E_>::type,
                             VUIdentity_<T_>,
                             VUExpand_<T_,
                                       typename boost::mpl::deref<B_>::type,
                                       typename boost::mpl::next<B_>::type, 
                                       E_> >::type {};

template <typename T_, typename A_>
class VectorInitializer :
  public VUVectorInitializerInternal_<T_,
                                      typename boost::mpl::begin<A_>::type,
                                      typename boost::mpl::end<A_>::type> {};

int test() {
  int kArray[3][2] = {{1,2}, {4, 5}, {6, 7}};
  vector<vector<int> > a =
    VectorInitializer<int, boost::mpl::vector_c<int, 3, 2> >().
    initialize(kArray);
}

コンパイルすると次のようなことを言われます。

vectorutil_test.cc:35: error: no matching function for call to 'VectorInitializer<int, boost::mpl::vector_c<int, 3l, 2l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l> >::initialize(int [3][2])'
vectorutil.h:42: note: candidates are: (以下略)

読めるように翻訳.

vectorutil_test.cc:35: error: no matching function for call to
'VectorInitializer<int, boost::mpl::vector_c<int, 3, 2> >::
  initialize(int [3][2])'
vectorutil.h:42: note: candidates are:
std::vector<typename VUVectorInitializerInternal_<T_, B_, E_>::result_type>
  VUExpand_<T_, NC_, B_, E_>::initialize(
    typename VUVectorInitializerInternal_<T_, B_, E_>::result_type*)
[
  with
    T_ = int,
    NC_ = mpl_::integral_c<int, 3>,
    B_ = boost::mpl::v_iter<boost::mpl::vector_c<int, 3, 2>, 1>,
    E_ = boost::mpl::v_iter<boost::mpl::vector_c<int, 3, 2>, 2>
]

引数のresult_type[3]がresult_type*になっています。つまり次の部分がまずくて、配列型ではなくてポインタになっていると。

  typedef typename child_type::result_type parameter_type[size];

つまり配列型と明示できていないか、あるいは配列型とポインタ型との区別がそもそも付かないか。

C/C++の多次元配列は苦手なので避けていました。その弊害が来たのでしょう。ということで勉強勉強。

こういうときこそマクロの出番かも。

悪気があったのではないのですが、私が見たマクロスの感想がこれなのでついコメン トしてしまいました。

勧められてしまったので見ないといけないようです。しかし、ひぐらしのゲームに15 分で飽きた私は、どうやってアニメを20話見ればいいのか。

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。