// Copyright Daniel Wallin, David Abrahams 2005. Use, modification and

// distribution is subject to 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 UNWRAP_CV_REFERENCE_050328_HPP

#define UNWRAP_CV_REFERENCE_050328_HPP



#include <boost/parameter/aux_/yesno.hpp>

#include <boost/mpl/bool.hpp>

#include <boost/mpl/identity.hpp>

#include <boost/mpl/eval_if.hpp>



namespace boost { template<class T> class reference_wrapper; }



namespace boost { namespace parameter { namespace aux {



//

// reference_wrapper support -- because of the forwarding problem,

// when passing arguments positionally by non-const reference, we

// ask users of named parameter interfaces to use ref(x) to wrap

// them.

//



// is_cv_reference_wrapper returns mpl::true_ if T is of type

// reference_wrapper<U> cv

template <class U>

yes_tag is_cv_reference_wrapper_check(reference_wrapper<U> const volatile*);

no_tag is_cv_reference_wrapper_check(...);



template <class T>

struct is_cv_reference_wrapper

{

    BOOST_STATIC_CONSTANT(

        bool, value = (

            sizeof(is_cv_reference_wrapper_check((T*)0)) == sizeof(yes_tag)

        )

    );



    typedef mpl::bool_<

#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))

        is_cv_reference_wrapper::

#endif 

    value> type;

};



#if BOOST_WORKAROUND(MSVC, == 1200)

template <>

struct is_cv_reference_wrapper<int>

  : mpl::false_ {};

#endif



// Needed for unwrap_cv_reference below. T might be const, so

// eval_if might fail because of deriving from T const on EDG.

template <class T>

struct get_type

{

    typedef typename T::type type;

};



#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))

template <class T, class is_reference_wrapper = typename is_cv_reference_wrapper<T>::type>

struct unwrap_cv_reference

{

    typedef T type;

};



template <class T>

struct unwrap_cv_reference<T const, mpl::false_>

{

    typedef T const type;

};



template <class T>

struct unwrap_cv_reference<T, mpl::true_>

  : T

{};



#else 

// Produces the unwrapped type to hold a reference to in named<>

// Can't use boost::unwrap_reference<> here because it

// doesn't handle the case where T = reference_wrapper<U> cv

template <class T>

struct unwrap_cv_reference

{

    typedef typename mpl::eval_if<

        is_cv_reference_wrapper<T>

      , get_type<T>

      , mpl::identity<T>

    >::type type;

};

#endif



}}} // namespace boost::parameter::aux



#endif // UNWRAP_CV_REFERENCE_050328_HPP



