/////////////////////////////////////////////////////////////////////////////// | |
/// \file decltype.hpp | |
/// Contains definition the BOOST_PROTO_DECLTYPE_() macro and assorted helpers | |
// | |
// Copyright 2008 Eric Niebler. Distributed under the Boost | |
// Software License, Version 1.0. (See accompanying file | |
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
#ifndef BOOST_PROTO_DETAIL_DECLTYPE_HPP_EAN_04_04_2008 | |
#define BOOST_PROTO_DETAIL_DECLTYPE_HPP_EAN_04_04_2008 | |
#include <boost/config.hpp> | |
#include <boost/detail/workaround.hpp> | |
#include <boost/get_pointer.hpp> | |
#include <boost/preprocessor/cat.hpp> | |
#include <boost/preprocessor/repetition/enum_params.hpp> | |
#include <boost/preprocessor/repetition/enum_trailing_params.hpp> | |
#include <boost/preprocessor/repetition/enum_binary_params.hpp> | |
#include <boost/preprocessor/repetition/repeat_from_to.hpp> | |
#include <boost/preprocessor/iteration/local.hpp> | |
#include <boost/mpl/if.hpp> | |
#include <boost/mpl/eval_if.hpp> | |
#include <boost/mpl/identity.hpp> | |
#include <boost/type_traits/is_class.hpp> | |
#include <boost/type_traits/remove_reference.hpp> | |
#include <boost/type_traits/is_pointer.hpp> | |
#include <boost/type_traits/is_function.hpp> | |
#include <boost/type_traits/is_member_object_pointer.hpp> | |
#include <boost/type_traits/add_const.hpp> | |
#include <boost/type_traits/add_reference.hpp> | |
#include <boost/typeof/typeof.hpp> | |
#include <boost/utility/addressof.hpp> | |
#include <boost/utility/result_of.hpp> | |
#include <boost/utility/enable_if.hpp> | |
#include <boost/proto/repeat.hpp> | |
#ifndef BOOST_NO_DECLTYPE | |
# define BOOST_PROTO_DECLTYPE_(EXPR, TYPE) typedef decltype(EXPR) TYPE; | |
#else | |
# define BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(NESTED, EXPR) \ | |
BOOST_TYPEOF_NESTED_TYPEDEF_TPL(BOOST_PP_CAT(nested_and_hidden_, NESTED), EXPR) \ | |
static int const sz = sizeof(boost::proto::detail::check_reference(EXPR)); \ | |
struct NESTED \ | |
: boost::mpl::if_c< \ | |
1==sz \ | |
, typename BOOST_PP_CAT(nested_and_hidden_, NESTED)::type & \ | |
, typename BOOST_PP_CAT(nested_and_hidden_, NESTED)::type \ | |
> \ | |
{}; | |
# define BOOST_PROTO_DECLTYPE_(EXPR, TYPE) \ | |
BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(BOOST_PP_CAT(nested_, TYPE), (EXPR)) \ | |
typedef typename BOOST_PP_CAT(nested_, TYPE)::type TYPE; | |
#endif | |
namespace boost { namespace proto | |
{ | |
namespace detail | |
{ | |
namespace anyns | |
{ | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
struct any | |
{ | |
any(...); | |
any operator=(any); | |
any operator[](any); | |
#define M0(Z, N, DATA) any operator()(BOOST_PP_ENUM_PARAMS_Z(Z, N, any BOOST_PP_INTERCEPT)); | |
BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, M0, ~) | |
#undef M0 | |
template<typename T> | |
operator T &() const volatile; | |
any operator+(); | |
any operator-(); | |
any operator*(); | |
any operator&(); | |
any operator~(); | |
any operator!(); | |
any operator++(); | |
any operator--(); | |
any operator++(int); | |
any operator--(int); | |
friend any operator<<(any, any); | |
friend any operator>>(any, any); | |
friend any operator*(any, any); | |
friend any operator/(any, any); | |
friend any operator%(any, any); | |
friend any operator+(any, any); | |
friend any operator-(any, any); | |
friend any operator<(any, any); | |
friend any operator>(any, any); | |
friend any operator<=(any, any); | |
friend any operator>=(any, any); | |
friend any operator==(any, any); | |
friend any operator!=(any, any); | |
friend any operator||(any, any); | |
friend any operator&&(any, any); | |
friend any operator&(any, any); | |
friend any operator|(any, any); | |
friend any operator^(any, any); | |
friend any operator,(any, any); | |
friend any operator->*(any, any); | |
friend any operator<<=(any, any); | |
friend any operator>>=(any, any); | |
friend any operator*=(any, any); | |
friend any operator/=(any, any); | |
friend any operator%=(any, any); | |
friend any operator+=(any, any); | |
friend any operator-=(any, any); | |
friend any operator&=(any, any); | |
friend any operator|=(any, any); | |
friend any operator^=(any, any); | |
}; | |
} | |
using anyns::any; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
struct as_mutable | |
{ | |
typedef T &type; | |
}; | |
template<typename T> | |
struct as_mutable<T &> | |
{ | |
typedef T &type; | |
}; | |
template<typename T> | |
struct as_mutable<T const &> | |
{ | |
typedef T &type; | |
}; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
T make(); | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
typename as_mutable<T>::type make_mutable(); | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
struct subscript_wrapper | |
: T | |
{ | |
using T::operator[]; | |
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) | |
any operator[](any const volatile &) const volatile; | |
#else | |
any operator[](any const &) const volatile; | |
#endif | |
}; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
struct as_subscriptable | |
{ | |
typedef | |
typename mpl::if_c< | |
is_class<T>::value | |
, subscript_wrapper<T> | |
, T | |
>::type | |
type; | |
}; | |
template<typename T> | |
struct as_subscriptable<T const> | |
{ | |
typedef | |
typename mpl::if_c< | |
is_class<T>::value | |
, subscript_wrapper<T> const | |
, T const | |
>::type | |
type; | |
}; | |
template<typename T> | |
struct as_subscriptable<T &> | |
{ | |
typedef | |
typename mpl::if_c< | |
is_class<T>::value | |
, subscript_wrapper<T> & | |
, T & | |
>::type | |
type; | |
}; | |
template<typename T> | |
struct as_subscriptable<T const &> | |
{ | |
typedef | |
typename mpl::if_c< | |
is_class<T>::value | |
, subscript_wrapper<T> const & | |
, T const & | |
>::type | |
type; | |
}; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
typename as_subscriptable<T>::type make_subscriptable(); | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
char check_reference(T &); | |
template<typename T> | |
char (&check_reference(T const &))[2]; | |
namespace has_get_pointerns | |
{ | |
using boost::get_pointer; | |
void *(&get_pointer(...))[2]; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
struct has_get_pointer | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = sizeof(void *) == sizeof(get_pointer(make<T &>()))); | |
typedef mpl::bool_<value> type; | |
}; | |
} | |
using has_get_pointerns::has_get_pointer; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
struct classtypeof; | |
template<typename T, typename U> | |
struct classtypeof<T U::*> | |
{ | |
typedef U type; | |
}; | |
#define BOOST_PP_LOCAL_MACRO(N) \ | |
template<typename T, typename U BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)> \ | |
struct classtypeof<T (U::*)(BOOST_PP_ENUM_PARAMS(N, A))> \ | |
{ \ | |
typedef U type; \ | |
}; \ | |
template<typename T, typename U BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)> \ | |
struct classtypeof<T (U::*)(BOOST_PP_ENUM_PARAMS(N, A)) const> \ | |
{ \ | |
typedef U type; \ | |
}; \ | |
/**/ | |
#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PROTO_MAX_ARITY) | |
#include BOOST_PP_LOCAL_ITERATE() | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T> | |
T &lvalue(T &t) | |
{ | |
return t; | |
} | |
template<typename T> | |
T const &lvalue(T const &t) | |
{ | |
return t; | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename U, typename V, typename T> | |
U *proto_get_pointer(T &t, V *, U *) | |
{ | |
return boost::addressof(t); | |
} | |
template<typename U, typename V, typename T> | |
U const *proto_get_pointer(T &t, V *, U const *) | |
{ | |
return boost::addressof(t); | |
} | |
template<typename U, typename V, typename T> | |
V *proto_get_pointer(T &t, V *, ...) | |
{ | |
return get_pointer(t); | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
#define BOOST_PROTO_USE_GET_POINTER() \ | |
using namespace boost::proto::detail::get_pointerns \ | |
/**/ | |
#define BOOST_PROTO_GET_POINTER(Type, Obj) \ | |
boost::proto::detail::proto_get_pointer<Type>( \ | |
boost::proto::detail::lvalue(Obj) \ | |
, (true ? 0 : get_pointer(Obj)) \ | |
, (true ? 0 : boost::addressof(boost::proto::detail::lvalue(Obj))) \ | |
) \ | |
/**/ | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
namespace get_pointerns | |
{ | |
using boost::get_pointer; | |
template<typename T> | |
typename disable_if_c<has_get_pointer<T>::value, T *>::type | |
get_pointer(T &t) | |
{ | |
return boost::addressof(t); | |
} | |
template<typename T> | |
typename disable_if_c<has_get_pointer<T>::value, T const *>::type | |
get_pointer(T const &t) | |
{ | |
return boost::addressof(t); | |
} | |
char test_ptr_to_const(void *); | |
char (&test_ptr_to_const(void const *))[2]; | |
template<typename U> char test_V_is_a_U(U *); | |
template<typename U> char test_V_is_a_U(U const *); | |
template<typename U> char (&test_V_is_a_U(...))[2]; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
// result_of_ is a wrapper around boost::result_of that also handles "invocations" of | |
// member object pointers. | |
template<typename T, typename Void = void> | |
struct result_of_ | |
: BOOST_PROTO_RESULT_OF<T> | |
{}; | |
template<typename T, typename U, typename V> | |
struct result_of_<T U::*(V), typename enable_if_c<is_member_object_pointer<T U::*>::value>::type> | |
{ | |
BOOST_STATIC_CONSTANT(bool, is_V_a_smart_ptr = 2 == sizeof(test_V_is_a_U<U>(&lvalue(make<V>())))); | |
BOOST_STATIC_CONSTANT(bool, is_ptr_to_const = 2 == sizeof(test_ptr_to_const(BOOST_PROTO_GET_POINTER(U, make<V>())))); | |
// If V is not a U, then it is a (smart) pointer and we can always return an lvalue. | |
// Otherwise, we can only return an lvalue if we are given one. | |
typedef | |
typename mpl::eval_if_c< | |
(is_V_a_smart_ptr || is_reference<V>::value) | |
, mpl::eval_if_c< | |
is_ptr_to_const | |
, add_reference<typename add_const<T>::type> | |
, add_reference<T> | |
> | |
, mpl::identity<T> | |
>::type | |
type; | |
}; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template< | |
typename T | |
, typename U | |
, bool IsMemPtr = is_member_object_pointer< | |
typename remove_reference<U>::type | |
>::value | |
> | |
struct mem_ptr_fun | |
{ | |
BOOST_PROTO_DECLTYPE_( | |
proto::detail::make_mutable<T>() ->* proto::detail::make<U>() | |
, result_type | |
) | |
result_type operator()( | |
typename add_reference<typename add_const<T>::type>::type t | |
, typename add_reference<typename add_const<U>::type>::type u | |
) const | |
{ | |
return t ->* u; | |
} | |
}; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename T, typename U> | |
struct mem_ptr_fun<T, U, true> | |
{ | |
typedef | |
typename classtypeof< | |
typename uncvref<U>::type | |
>::type | |
V; | |
BOOST_PROTO_DECLTYPE_( | |
BOOST_PROTO_GET_POINTER(V, proto::detail::make_mutable<T>()) ->* proto::detail::make<U>() | |
, result_type | |
) | |
result_type operator()( | |
typename add_reference<typename add_const<T>::type>::type t | |
, U u | |
) const | |
{ | |
return BOOST_PROTO_GET_POINTER(V, t) ->* u; | |
} | |
}; | |
} | |
using get_pointerns::result_of_; | |
using get_pointerns::mem_ptr_fun; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
template<typename A0, typename A1> | |
struct comma_result | |
{ | |
BOOST_PROTO_DECLTYPE_((proto::detail::make<A0>(), proto::detail::make<A1>()), type) | |
}; | |
template<typename A0> | |
struct comma_result<A0, void> | |
{ | |
typedef void type; | |
}; | |
template<typename A1> | |
struct comma_result<void, A1> | |
{ | |
typedef A1 type; | |
}; | |
template<> | |
struct comma_result<void, void> | |
{ | |
typedef void type; | |
}; | |
//////////////////////////////////////////////////////////////////////////////////////////// | |
// normalize a function type for use with boost::result_of | |
template<typename T, typename U = T> | |
struct result_of_fixup | |
: mpl::if_c<is_function<T>::value, T *, U> | |
{}; | |
template<typename T, typename U> | |
struct result_of_fixup<T &, U> | |
: result_of_fixup<T, T> | |
{}; | |
template<typename T, typename U> | |
struct result_of_fixup<T const &, U> | |
: result_of_fixup<T, T> | |
{}; | |
template<typename T, typename U> | |
struct result_of_fixup<T *, U> | |
: result_of_fixup<T, U> | |
{}; | |
template<typename R, typename T, typename U> | |
struct result_of_fixup<R T::*, U> | |
{ | |
typedef R T::*type; | |
}; | |
template<typename T, typename U> | |
struct result_of_fixup<T const, U> | |
: result_of_fixup<T, U> | |
{}; | |
//// Tests for result_of_fixup | |
//struct bar {}; | |
//BOOST_MPL_ASSERT((is_same<bar, result_of_fixup<bar>::type>)); | |
//BOOST_MPL_ASSERT((is_same<bar const, result_of_fixup<bar const>::type>)); | |
//BOOST_MPL_ASSERT((is_same<bar, result_of_fixup<bar &>::type>)); | |
//BOOST_MPL_ASSERT((is_same<bar const, result_of_fixup<bar const &>::type>)); | |
//BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(*)()>::type>)); | |
//BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(* const)()>::type>)); | |
//BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(* const &)()>::type>)); | |
//BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(&)()>::type>)); | |
template<typename T, typename PMF> | |
struct memfun | |
{ | |
typedef typename uncvref<PMF>::type pmf_type; | |
typedef typename classtypeof<pmf_type>::type V; | |
typedef typename BOOST_PROTO_RESULT_OF<pmf_type(T)>::type result_type; | |
memfun(T t, PMF p) | |
: obj(t) | |
, pmf(p) | |
{} | |
result_type operator()() const | |
{ | |
BOOST_PROTO_USE_GET_POINTER(); | |
return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)(); | |
} | |
#define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a) \ | |
template<typename_A(N)> \ | |
result_type operator()(A_const_ref_a(N)) const \ | |
{ \ | |
BOOST_PROTO_USE_GET_POINTER(); \ | |
return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)(a(N)); \ | |
} \ | |
/**/ | |
#define BOOST_PROTO_LOCAL_a BOOST_PROTO_a | |
#define BOOST_PROTO_LOCAL_LIMITS (1, BOOST_PROTO_MAX_ARITY) | |
#include BOOST_PROTO_LOCAL_ITERATE() | |
private: | |
T obj; | |
PMF pmf; | |
}; | |
} // namespace detail | |
}} | |
#endif |