Boost.ConceptTraits(没になったのかどうか知らないけど、正式入りしてないライブラリ)
にis_assignableがあったので、抜き出して試してみました。(VC++8.0)
#include <boost/static_assert.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/and.hpp> #include <boost/mpl/or.hpp> #include <boost/mpl/not.hpp> namespace shand { namespace assignable_detail { template <class T> struct remove_r : boost::remove_reference<T> {}; template <class T> struct remove_cvr : boost::remove_cv<typename boost::remove_reference<T>::type> {}; template <class T> struct remove_cvpr : boost::remove_cv< typename boost::remove_pointer< typename remove_r<T>::type >::type > {}; template<class T> struct is_not_const : boost::mpl::not_< boost::is_const<typename remove_r<T>::type> > {}; template<class T,class U> struct is_object_and_not_array_or_member_function_pointer_and_same_type : boost::mpl::and_< boost::mpl::or_< boost::mpl::and_< boost::is_object<typename remove_r<T>::type>, boost::mpl::not_< boost::is_array<typename remove_r<T>::type> > >, boost::is_member_function_pointer<typename remove_r<T>::type> >, boost::is_same< typename remove_cvr<T>::type, typename remove_cvr<U>::type > > {}; template<class T> struct is_arithmetic_or_enum : boost::mpl::or_<boost::is_arithmetic<T>, boost::is_enum<T> > {}; template<class T,class U> struct is_arithmetic_and_arithmetic_or_enum : boost::mpl::and_< boost::is_arithmetic<typename remove_r<T>::type>, is_arithmetic_or_enum<typename remove_r<U>::type> > {}; template<class T> struct is_object_pointer : boost::mpl::and_< boost::is_pointer<T>, boost::mpl::not_< boost::is_function<typename boost::remove_pointer<T>::type> > > {}; template<class T,class U> struct is_compatible_object_pointers : boost::mpl::and_< is_object_pointer<typename remove_r<U>::type>, boost::mpl::or_< boost::is_same<typename remove_cvr<T>::type, void*>, boost::is_base_and_derived< typename remove_cvpr<T>::type, typename remove_cvpr<U>::type > > > {}; template<class T,class U> struct is_compatible_pointers : boost::mpl::and_< boost::is_pointer<typename boost::remove_reference<T>::type>, boost::mpl::or_< boost::is_same< boost::remove_cv<typename remove_r<T>::type>, boost::remove_cv<typename remove_r<U>::type> >, is_compatible_object_pointers<T,U> > > {}; template<class T> struct is_class_or_union_ : boost::mpl::or_< boost::is_class<T>, boost::is_union<T> > {}; }} // namespace shand::detail namespace shand { template<class T,class U = T> struct is_assignable : boost::mpl::and_< assignable_detail::is_not_const<typename boost::remove_reference<T>::type>, boost::mpl::or_< assignable_detail::is_object_and_not_array_or_member_function_pointer_and_same_type<T,U>, assignable_detail::is_arithmetic_and_arithmetic_or_enum<T,U>, assignable_detail::is_compatible_pointers<T,U>, assignable_detail::is_class_or_union_<typename boost::remove_reference<T>::type> > > {}; } // namespace shand struct A {}; struct B { int& r; }; struct C { private: C& operator=(const C&); // 宣言して定義しない }; int main() { BOOST_STATIC_ASSERT(shand::is_assignable<int>::value); // OK BOOST_STATIC_ASSERT(shand::is_assignable<int*>::value); // OK BOOST_STATIC_ASSERT(shand::is_assignable<A>::value); // OK BOOST_STATIC_ASSERT(shand::is_assignable<B>::value); // OK : エラーになってほしい BOOST_STATIC_ASSERT(shand::is_assignable<C>::value); // OK : リンク時なのでこれはどちらにしろ無理 // BOOST_STATIC_ASSERT(shand::is_assignable<const int>::value); // NG }
というか、非constのクラスなら通るようになってるから無理か。
これ書いてる間に別な案を考えたので明日あたり試してみよう。
追記:
BOOST_FUSION_ADAPT_STRUCTで、クラスメンバを型リストに変換し、
参照とconstのメンバを探す、というのをやろうと思ったけど
BOOST_FUSION_ADAPT_STRUCTの引数でメンバの型を書かないといけないのと、
参照を指定することができなかったので断念。