Rangeの要素をstatic_castとかdynamic_castする
Rangeの要素の型を変換したいと思ったときに、Ovenのconverted Rangeアダプタだと、implicit_castしかできなくて、static_castとかdynamic_castとかできないので、できたらいいなと思った。
transformedと関数オブジェクトとかboost::lambda::ll_static_castとかでなんやかんやすればできるけど、それを毎回書いていられないので、Rangeアダプタにまとめてしまおうと。
(ただし、egg周りの実装が全然把握できてなくて、converted Rangeアダプタの実装を元にして作りましたけど、なにがどうなっているかちゃんと分かっていません。)
hwm/detail/XXX_cast.hpp
#ifndef HWM_XXX_CAST_TYPE #error no cast type specified #endif #include <boost/preprocessor/cat.hpp> #define HWM_DETAIL_XXX_CASTED BOOST_PP_CAT(HWM_XXX_CAST_TYPE, ed) #define HWM_DETAIL_XXX_CASTED_DETAIL BOOST_PP_CAT(HWM_DETAIL_XXX_CASTED, _detail) #define HWM_DETAIL_MAKE_XXX_CASTED BOOST_PP_CAT(X_make_, HWM_DETAIL_XXX_CASTED) #include <pstade/egg/function.hpp> #include <pstade/egg/pipable.hpp> #include <pstade/oven/transformed.hpp> namespace hwm { namespace HWM_DETAIL_XXX_CASTED_DETAIL { using namespace pstade; using namespace pstade::oven; template<typename To> struct little { template<typename CastTo> struct cast { typedef CastTo result_type; template<typename T> result_type operator()(T const &t) const { return HWM_XXX_CAST_TYPE<To>(t); } template<typename T> result_type operator()(T &t) const { return HWM_XXX_CAST_TYPE<To>(t); } }; template<typename Myself, typename Range> struct apply : result_of< X_make_transformed<To>( Range &, cast<To>) > {}; template<typename Result, typename Range> Result call(Range &rng) const { return X_make_transformed<To>()( rng, cast<To>() ); } }; } //namespace HWM_DETAIL_XXX_CASTED_DETAIL template<typename To> struct HWM_DETAIL_MAKE_XXX_CASTED : pstade::egg::function<HWM_DETAIL_XXX_CASTED_DETAIL::little<To> > {}; template<typename To> struct HWM_DETAIL_XXX_CASTED : pstade::egg::result_of_pipable<HWM_DETAIL_MAKE_XXX_CASTED<To> >::type , pstade::egg::lookup_pipable_operator {}; } //namespace hwm #undef HWM_XXX_CAST_TYPE #undef HWM_DETAIL_XXX_CASTED #undef HWM_DETAIL_XXX_CASTED_DETAIL #undef HWM_DETAIL_MAKE_XXX_CASTED
hwm/static_casted.hpp
#ifndef HWM_STATIC_CASTED_HPP #define HWM_STATIC_CASTED_HPP #define HWM_XXX_CAST_TYPE static_cast #include "./detail/XXX_casted.hpp" #endif //HWM_STATIC_CASTED_HPP
hwm/dynamic_casted.hpp
hwm/reinterpret_casted.hpp
hwm/const_casted.hpp
もそんな感じ
hwm/casted.hpp
#ifndef HWM_CASTED_HPP #define HWM_CASTED_HPP #include "./static_casted.hpp" #include "./dynamic_casted.hpp" #include "./reinterpret_casted.hpp" #include "./const_casted.hpp" #endif //HWM_CASTEAD_HPP
これで、castが出来ます。
#include <iostream> #include <vector> #include <pstade/oven/io.hpp> //インクルードパスとかなんとなく空気読んでくだしあ。 #include <hwm/casted.hpp> void static_casted_test() { std::vector<int> is; for(int i = 0; i < 5; ++i) { is.push_back(-i); } namespace oven = pstade::oven; std::cout << (is | hwm::static_casted<unsigned char>() | hwm::static_casted<unsigned int>()) << std::endl; } struct X { virtual ~X() {} friend std::ostream & operator<< (std::ostream &os, X const &x) { return os << "A as X"; } protected: X() {} }; struct Y { virtual ~Y() {} friend std::ostream & operator<< (std::ostream &os, Y const &y) { return os << "A as Y"; } protected: Y() {} }; struct Z { virtual ~Z() {} friend std::ostream & operator<< (std::ostream &os, Z const &z) { return os << "A as Z"; } protected: Z() {} }; struct A : X, Y, Z {}; #include <boost/make_shared.hpp> #include <pstade/oven/constants.hpp> #include <pstade/oven/indirected.hpp> void dynamic_casted_test() { std::vector<boost::shared_ptr<X> > xs; for(int i = 0; i < 3; ++i) { xs.push_back(boost::make_shared<A>()); } namespace oven = pstade::oven; std::cout << (xs | oven::indirected | hwm::dynamic_casted<X const &>()) << std::endl; std::cout << (xs | oven::indirected | hwm::dynamic_casted<Y &>()) << std::endl; std::cout << (xs | oven::indirected | hwm::dynamic_casted<Y &>() | hwm::dynamic_casted<Z &>()) << std::endl; //compilation error.(expected) //std::cout << (xs | oven::indirected | oven::constants | hwm::dynamic_casted<Y &>()) << std::endl; std::cout << (xs | oven::indirected | oven::constants | hwm::dynamic_casted<Y const &>()) << std::endl; } #include <pstade/oven/outdirected.hpp> #include <pstade/oven/pointed.hpp> #include <pstade/oven/transformed.hpp> struct to_str { typedef std::string result_type; result_type operator() (char const *s) const { return std::string(s, s+4); } }; void reinterpret_casted_test() { namespace oven = pstade::oven; typedef union { int magic_; char fourcc_[4]; } fcc_t; std::vector<int> is; fcc_t fcc; fcc.fourcc_[0] = 'R'; fcc.fourcc_[1] = 'I'; fcc.fourcc_[2] = 'F'; fcc.fourcc_[3] = 'F'; is.push_back(fcc.magic_); fcc.fourcc_[0] = 'W'; fcc.fourcc_[1] = 'A'; fcc.fourcc_[2] = 'V'; fcc.fourcc_[3] = 'E'; is.push_back(fcc.magic_); fcc.fourcc_[0] = 'f'; fcc.fourcc_[1] = 'm'; fcc.fourcc_[2] = 't'; fcc.fourcc_[3] = ' '; is.push_back(fcc.magic_); std::cout << (is | oven::pointed | oven::outdirected | hwm::reinterpret_casted<char const *>() | oven::transformed(to_str())) << std::endl; } struct B { friend std::ostream & operator<< (std::ostream &os, B const &b) { return os << "const version is called#B"; } friend std::ostream & operator<< (std::ostream &os, B &b) { return os << "non-const version is called#B"; } }; #include <pstade/oven/identities.hpp> void const_casted_test() { namespace oven = pstade::oven; std::vector<B> const bs(3); std::cout << (bs | oven::identities) << std::endl; std::cout << (bs | hwm::const_casted<B &>()) << std::endl; } int main() { static_casted_test(); dynamic_casted_test(); reinterpret_casted_test(); const_casted_test(); }
出力
{0,255,254,253,252} {A as X,A as X,A as X} {A as Y,A as Y,A as Y} {A as Z,A as Z,A as Z} {A as Y,A as Y,A as Y} {RIFF,WAVE,fmt } {const version is called#B,const version is called#B,const version is called#B} {non-const version is called#B,non-const version is called#B,non-const version is called#B}
で、とりあえず書いてみましたが、バグがあるかもしれません。
使う人がいたら自己責任ということでよろしくです。