前の配列→vector変換の記事に、配列にこだわらなければコンテナの初期化は「それboostでできるよ」のつっこみがありました。
ありました。
ちなみに前に調べたときは見つからなかったんですよ。絶対あるとは思っていたのですが。
前回の話: C++で多次元のvectorを多次元の配列で初期化したいのですが、どうしたらマクロを使わずにできるでしょう。
リンク先のように書けばうまく動きました。これでboost::mplも、マクロも書かなくてすみます。助かりました。
- 追記(2009.11.29 20:00): 解答編ができました。
目標. 次のようなものをつくる。
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++の多次元配列は苦手なので避けていました。その弊害が来たのでしょう。ということで勉強勉強。
こういうときこそマクロの出番かも。
悪気があったのではないのですが、私が見たマクロスの感想がこれなのでついコメン トしてしまいました。
- はてなキーワー ドのarchive.org
- リンク切れていたらarchive.orgの元ページから2007年度のどこかのリビジョンを。
- 現在の版との差がすごい。
勧められてしまったので見ないといけないようです。しかし、ひぐらしのゲームに15 分で飽きた私は、どうやってアニメを20話見ればいいのか。
ICFPCのvisualiserをjavascript + canvasで再生産してみました。firefox 3.0.10とGoogle Chrome Linux 3.0.190.2で検証。IEは無理です。Safari 4 winとfirefox 3.0は遅くて、Chromeかfirefox 3.5ならまともに動きます。
手元に本番提出データがなかったので実験用のデータを適当に使っています。まだtargetが12個あると思っていたときのデータです。
正直重すぎます。軌跡を書くところだけが重いのでここを再利用できると良いのですが。
javascriptなんて殆どまともに書いてないのできっちりと罠にかかりました。
- context.beginPath(), moveTo, lineTo, closePathまでやってfillを忘れる。
- closePathの役目はglEndではない。終点と始点とを繋げる。
- 関数を呼ぶ代わりに関数を渡してしまう。その逆も。
- javascriptを編集してからリロードをかけると時々firebugが発狂。
- functionのスコープ。これは知っていたので回避。
- 別のタブであらためてロードすると大丈夫だったり。
- 配列をfor in で回ろうとする。
- onmousedownで渡されるイベントからクリックされた場所を探す方法。
- とりあえずここに従ってみた。http://d.hatena.ne.jp/TakiTake/20081014/p1
- onmousedown, onmousemove, onmouseupだけじゃなくてonmouseoutも使うとよい。
- cssはコピペ。
ネット上にものすごい勢いで情報があるので、調べながらやってもそれほど難しくはありませんでした。スクロールバーなど一部は明らかにやっつけですが。