mpl::switch_ で、タグディスパッチ
んーこれであってるのかな?
何気にタグディスパッチは初めて使ったかも知れない。
mpl::switch_ と組み合わせてみました。
#include <boost/mpl/has_xxx.hpp> #include <boost/mpl/switch.hpp> #include <boost/mpl/always.hpp> #include <boost/mpl/vector.hpp> namespace mpl = boost::mpl; template<typename Vec, int N> struct at_c_impl{ BOOST_MPL_HAS_XXX_TRAIT_DEF(at); BOOST_MPL_HAS_XXX_TRAIT_DEF(at_x); BOOST_MPL_HAS_XXX_TRAIT_DEF(at_y); struct at_tag{}; struct at_x_tag{}; struct at_y_tag{}; struct default_tag{}; // 複数の条件から、使用する tag を取得する typedef mpl::vector< mpl::pair<has_at<mpl::_1>, mpl::always<at_tag> >, mpl::pair<mpl::always<mpl::bool_<N == 0> >, mpl::always<at_x_tag > >, mpl::pair<mpl::always<mpl::bool_<N == 1> >, mpl::always<at_y_tag > >, mpl::pair<mpl::always<mpl::true_>, mpl::always<default_tag> > > tags; typedef typename Vec::value_type const& result_type; result_type operator ()(Vec const& vec) const{ return (*this)(vec, typename mpl::switch_<tags, Vec>::type()); }; private: // tag によって処理を切り替える result_type operator ()(Vec const& vec, at_tag) const{ return typename Vec::at()(vec, N); }; result_type operator ()(Vec const& vec, at_x_tag) const{ return typename Vec::at_x()(vec); }; result_type operator ()(Vec const& vec, at_y_tag) const{ return typename Vec::at_y()(vec); }; result_type operator ()(Vec const& vec, default_tag) const{ // なんか適当な処理 return vec[N]; }; }; template<int N, typename Vec> typename at_c_impl<Vec, N>::result_type at_c(Vec const& vec){ return at_c_impl<Vec, N>()(vec); } #include <iostream> struct vec2{ typedef float value_type; value_type x, y; // has_xxx で判定するので、関数オブジェクト struct at_x{ value_type const& operator ()(vec2 const& vec) const{ return vec.x; } }; struct at_y{ value_type const& operator ()(vec2 const& vec) const{ return vec.y; } }; }; struct vec3{ typedef float value_type; value_type value[3]; // has_xxx で判定するので、関数オブジェクト struct at{ value_type const& operator ()(vec3 const& vec, int n) const{ return vec.value[n]; } }; // 複数定義されていても、at が優先的に使用される struct at_x{ value_type const& operator ()(vec3 const& vec) const{ // テスト用 static value_type test = 9.99999f; return test; // return vec.value[0]; } }; }; int main(){ vec3 v3 = {{ 1.0f, 2.0f, 3.0f }}; std::cout << at_c<0>(v3) << std::endl; // != 9.99999f std::cout << at_c<1>(v3) << std::endl; std::cout << at_c<2>(v3) << std::endl; vec2 v2 = {3.14f, 3.14f}; std::cout << at_c<0>(v2) << std::endl; std::cout << at_c<1>(v2) << std::endl; return 0; }
[出力]
1 2 3 3.14 3.14
んーこんな感じでしょうか。
Vec::at が定義されていれば、そちらを優先的に使用し、Vec::at_x が定義されていれば、そちらを使用します。
at_x を実装するならその逆
class ないで、オブジェクト関数を定義しているのは、has_xxx で、判断を行う為です。
ちょっとめんどくさいけどこれが確実かな?
複数条件で、SFINAE する場合はこっちの方が楽かも知れない。
[boost]
ver 1.46.1