ある型 T に対して
- T の左辺値
- T の const 左辺値
- T の右辺値
- T に変換可能な(ただし T 自身ではない)型の値
- T に変換可能でない型
以上を識別したい,というモチベーションに関する実験メモ.
MSVC 7.1 と GCC 3.4.4 で確認済み.要 Boost 1.33.0.
#include <iostream> #include <boost/mpl/eval_if.hpp> #include <boost/mpl/identity.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/add_reference.hpp> #include <boost/type_traits/remove_cv.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/utility/enable_if.hpp> template<class T> class move_from { public: move_from(T *src) : p_(src) {} private: T *p_; }; template<class T> struct is_movable : public boost::is_convertible<T, move_from<T> > {}; template<class T> struct move_return_type : public boost::mpl::eval_if< is_movable<T> , boost::mpl::identity<T> , boost::add_reference<T> > {}; template<class T> move_from<T> move_dispatch(T &x, boost::mpl::true_ is_movable) { return move_from<T>(&x); } template<class T> T &move_dispatch(T &x, boost::mpl::false_ is_movable) { return x; } template<class T> typename move_return_type<T>::type move(T &x) { return move_dispatch(x, typename is_movable<T>::type()); } template<class T> struct plain : public boost::remove_cv< typename boost::remove_reference<T>::type > {}; template<class T, class U, class R = void> struct enable_if_same : public boost::enable_if<boost::is_same<T, U>, R> {}; template<class T, class U, class R = void> struct disable_if_same : public boost::disable_if<boost::is_same<T, U>, R> {}; template<class T, class U, class R = void> struct enable_if_convertible : public boost::enable_if<boost::is_convertible<T, U>, R> {}; template<class T, class U, class R = void> struct disable_if_convertible : public boost::disable_if<boost::is_convertible<T, U>, R> {}; class another_type { public: another_type() {} another_type(another_type const &) { std::cout << "another_type のコピーコンストラクタ" << std::endl; } }; class irrelevant_type { public: irrelevant_type() {} irrelevant_type(irrelevant_type const &) {} }; class movable_type { public: movable_type() {} movable_type(movable_type const &) { std::cout << "movable_type のコピーコンストラクタ" << std::endl; } movable_type(another_type const &) { std::cout << "another_type から movable_type への変換コンストラクタ" << std::endl; } movable_type(move_from<movable_type> src) { std::cout << "movable_type の move コンストラクタ" << std::endl; } operator move_from<movable_type>() { return move_from<movable_type>(this); } }; movable_type rvalue() { movable_type m; return move(m); } movable_type const const_rvalue() { movable_type m; return move(m); } another_type another_rvalue() { another_type a; return a; } another_type const another_const_rvalue() { another_type a; return a; } irrelevant_type irrelevant_rvalue() { irrelevant_type i; return i; } irrelevant_type const irrelevant_const_rvalue() { irrelevant_type i; return i; } template<class T> void discriminate( T &x , typename enable_if_same<T, movable_type>::type * = 0 ) { std::cout << "movable_type の非 const 左辺値" << std::endl; } template<class T> void discriminate( T &x , typename enable_if_same<T, movable_type const>::type * = 0 ) { std::cout << "movable_type の const 左辺値" << std::endl; } void discriminate(move_from<movable_type> x) { std::cout << "movable_type の非 const 右辺値,もしくは明示的な move" << std::endl; } template<class T> void discriminate( T const &x , typename disable_if_same<typename plain<T>::type, movable_type>::type * = 0 , typename enable_if_convertible<T, movable_type>::type * =0 ) { std::cout << "movable_type へ変換可能な型.ただし,movable_type 自身ではない" << std::endl; } template<class T> void discriminate( T const & , typename disable_if_convertible<typename plain<T>::type, movable_type>::type * = 0 ) { std::cout << "movable_type へ変換不可能な型" << std::endl; } int main() { using namespace std; movable_type lvalue; discriminate(lvalue); cout << endl; movable_type const const_lvalue; discriminate(const_lvalue); cout << endl; movable_type lvalue2; discriminate(move(lvalue2)); cout << endl; movable_type const const_lvalue2; discriminate(move(const_lvalue2)); cout << endl; discriminate(rvalue()); cout << endl; discriminate(const_rvalue()); cout << endl; another_type another_lvalue; discriminate(another_lvalue); cout << endl; another_type const another_const_lvalue; discriminate(another_const_lvalue); cout << endl; discriminate(another_rvalue()); cout << endl; discriminate(another_const_rvalue()); cout << endl; irrelevant_type irrelevant_lvalue; discriminate(irrelevant_lvalue); cout << endl; irrelevant_type const irrelevant_const_lvalue; discriminate(irrelevant_const_lvalue); cout << endl; discriminate(irrelevant_rvalue()); cout << endl; discriminate(irrelevant_const_rvalue()); cout << endl; }