構造体のメンバ変数を定数の値で取得したい その2
前回の続きです。
コメントにも頂きましたが、std::mt の年と月のデータは特殊で、そのまま渡しても正しい値として認識がされません。
ですので、変数に渡す場合は、差分を計算して、代入しなければなりません。
std::tm st; st.tm_year = 2010 - 1900; // 1900年 が 0 なので st.tm_mon = 12 - 1; // 同じく 1月 が 0
しかし、代入するたびに差分を計算するのも手間なのでちょっと改造。
#include <iostream> #include <ctime> #include <boost/assert.hpp> #include <boost/multi_index/member.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/at.hpp> namespace multi_index = boost::multi_index; namespace mpl = boost::mpl; typedef mpl::int_<0> year; typedef mpl::int_<1> month; typedef mpl::int_<2> day; typedef mpl::int_<3> hour; typedef mpl::int_<4> minute; typedef mpl::int_<5> second; namespace detail{ typedef mpl::vector< multi_index::member<std::tm, int, &std::tm::tm_year>, multi_index::member<std::tm, int, &std::tm::tm_mon >, multi_index::member<std::tm, int, &std::tm::tm_mday>, multi_index::member<std::tm, int, &std::tm::tm_hour>, multi_index::member<std::tm, int, &std::tm::tm_min >, multi_index::member<std::tm, int, &std::tm::tm_sec > >::type tm_members_type; template<typename index> struct holder{ typedef index index_type; explicit holder(std::tm& st_) : st(st_){} operator int() const{ return get(index_type()); } holder& operator =(int const& rhs){ set(index_type(), rhs); return *this; } private: std::tm& st; template<typename index> void set(index&, int const& value){ mpl::at<detail::tm_members_type, index>::type()(st) = value; } template<typename index> int const& get(index&) const{ return mpl::at<detail::tm_members_type, index>::type()(st); } // 差分が必要な値のオーバーロード void set(year&, int const& value){ mpl::at<detail::tm_members_type, index>::type()(st) = value - 1900; } int get(year&) const{ return mpl::at<detail::tm_members_type, index>::type()(st) + 1900; } void set(month&, int const& value){ mpl::at<detail::tm_members_type, index>::type()(st) = value - 1; } int get(month&) const{ return mpl::at<detail::tm_members_type, index>::type()(st) + 1; } }; } // namespace detail template<typename index> detail::holder<index> tm_cast(std::tm& st){ return detail::holder<index>(st); } int main(){ std::tm st; tm_cast<year> (st) = 2010; tm_cast<month> (st) = 12; tm_cast<day> (st) = 25; tm_cast<hour> (st) = 9; tm_cast<minute>(st) = 12; tm_cast<second>(st) = 49; // tm_cast<year>(st) は、tm_year + 1900 の値が返ってくるので不正 // BOOST_ASSERT(( st.tm_year == tm_cast<year>(st) )); BOOST_ASSERT( st.tm_year == (2010 - 1900) ); BOOST_ASSERT( st.tm_mon == (12 - 1) ); BOOST_ASSERT( st.tm_sec == 49 ); std::cout << tm_cast<year> (st) << "-" << tm_cast<month> (st) << "-" << tm_cast<day> (st) << "-" << tm_cast<hour> (st) << "-" << tm_cast<minute>(st) << "-" << tm_cast<second>(st) << std::endl; return 0; }
std::mt を detail::holder でラップして、各値の設定と取得が出来るようにしました。
メンバ変数のポインタが取得できないこと以外は、前回と使い方は同じです。
今回は、2つしかなかったので、オーバーロードで処理の分岐をさせましたが、将来的に他の値でも差分が必要になってくるようならば、まとめて差分の値を定義しておくのもいいかもしれない。
std::tm に限らず、人間が扱うデータと、実際に処理するデータで値が違うことはよくあるので、もうちょっと汎用的に使えるようにしたい。
0から始まるのと1から始まるのでも全然違いますからねぇー。