/* Copyright 2003-2011 Joaquin M Lopez Munoz.
 * 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)
 *
 * See http://www.boost.org/libs/multi_index for library home page.
 */

#ifndef BOOST_MULTI_INDEX_MEM_KEY_HPP
#define BOOST_MULTI_INDEX_MEM_KEY_HPP

#if defined(_MSC_VER)&&(_MSC_VER>=1200)
#pragma once
#endif

#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/static_assert.hpp>

namespace boost{

namespace multi_index{

/* mem_key acts as a proxy to member, const_mem_fun or mem_fun according to
 * the type and object passed:
 *   mem_key<T C::*,ptr>          --> member<C,T,ptr>
 *   mem_key<T (C::*)()const,ptr> --> const_mem_fun<C,T,ptr>
 *   mem_key<T (C::*)(),ptr>      --> mem_fun<C,T,ptr>
 */

#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)

namespace detail{

template<typename PtrToMemberType,PtrToMemberType>
struct mem_key_invalid_type
{
  BOOST_STATIC_ASSERT(sizeof(PtrToMemberType)==0);
};

} /* namespace multi_index::detail */

template<typename PtrToMemberType,PtrToMemberType PtrToMember>
struct mem_key:detail::mem_key_invalid_type<PtrToMemberType,PtrToMember>
{};

template<typename Class,typename Type,Type Class::* PtrToMember>
struct mem_key<Type Class::*,PtrToMember>:
  member<Class,Type,PtrToMember>
{};

template<
  typename Class,typename Type,Type (Class::*PtrToMemberFunction)()const
>
struct mem_key<Type (Class::*)()const,PtrToMemberFunction>:
  const_mem_fun<Class,Type,PtrToMemberFunction>
{};

template<typename Class,typename Type,Type (Class::*PtrToMemberFunction)()>
struct mem_key<Type (Class::*)(),PtrToMemberFunction>:
  mem_fun<Class,Type,PtrToMemberFunction>
{};

#else /* defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) */

template<typename PtrToMemberType,PtrToMemberType PtrToMember>
struct mem_key
{
  /* mem_key not supported with this compiler */
  BOOST_STATIC_ASSERT(sizeof(PtrToMemberType)==0);
};

#endif

/* If decltype is available BOOST_MULTI_INDEX_AUTO_KEY allows for the
 * specification a member key without writing the type of the key, thus
 * getting maximum economy of expression.
 */

#if !defined(BOOST_NO_DECLTYPE)
#define BOOST_MULTI_INDEX_AUTO_KEY(PtrToMember) \
::boost::multi_index::mem_key<decltype(PtrToMember),PtrToMember>
#endif

} /* namespace multi_index */

} /* namespace boost */

#endif

