/* Copyright (C) 2010 and 2011 Chris Vine

The library comprised in this file or of which this file is part is
distributed by Chris Vine under the GNU Lesser General Public
License as follows:

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License, version 2.1, for more details.

   You should have received a copy of the GNU Lesser General Public
   License, version 2.1, along with this library (see the file LGPL.TXT
   which came with this source code package in the c++-gtk-utils
   sub-directory); if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

However, it is not intended that the object code of a program whose
source code instantiates a template from this file or uses macros or
inline functions (of any length) should by reason only of that
instantiation or use be subject to the restrictions of use in the GNU
Lesser General Public License.  With that in mind, the words "and
macros, inline functions and instantiations of templates (of any
length)" shall be treated as substituted for the words "and small
macros and small inline functions (ten lines or less in length)" in
the fourth paragraph of section 5 of that licence.  This does not
affect any other reason why object code may be subject to the
restrictions in that licence (nor for the avoidance of doubt does it
affect the application of section 2 of that licence to modifications
of the source code in this file).

*/

#ifndef CGU_PARAM_H
#define CGU_PARAM_H

#include <c++-gtk-utils/cgu_config.h>

namespace Cgu {

/**
 * @class Param param.h c++-gtk-utils/param.h
 * @brief Struct for automatic typing of function parameter arguments
 *
 * @details This struct uses template partial specialisation in order
 * to provide automatic type mapping for function arguments.  It is
 * used by the unbound arguments of callback objects and their related
 * functors and emitter objects.  (A more detailed explanation is that
 * it is used where a virtual function is at the end of a call chain,
 * notably the dispatch() method of callback objects, with the result
 * that we cannot templatise the virtual function itself in order to
 * use std::forward for argument passing, but instead have to type-map
 * the arguments using class templates.)
 *
 * Mapping is as follows:
 *
 *  A value argument is mapped to reference to const of the value
 *  type.
 *
 *  A pointer argument is mapped to pointer argument (its original
 *  type).
 *
 *  A non-const reference argument is mapped to non-const reference
 *  (its original type).
 *
 *  A const reference argument is mapped to const reference (its
 *  original type).
 */

template<class T>
struct Param {
  typedef const T& ParamType;
};

template<class T>
struct Param<T&> {
  typedef T& ParamType;
};

template<class T>
struct Param<T*> {
  typedef T* ParamType;
};

/**
 * @class RemoveRefCond param.h c++-gtk-utils/param.h
 * @brief Struct which will conditionally convert a reference type to
 * a value type
 *
 * @details This struct is used by Callback::make(),
 * Callback::make_val() and Callback::make_ref() so that where a call
 * is made to Callback::make_ref() and the target function's arguments
 * include one with a reference, that reference is removed.
 *
 * Since 2.0.0-rc3
 */
template<class T, bool unref>
struct RemoveRefCond {};

template<class T>
struct RemoveRefCond<T, true> {
  typedef T Type;
};

template<class T>
struct RemoveRefCond<T&, true> {
  typedef T Type;
};

template<class T>
struct RemoveRefCond<T, false> {
  typedef T Type;
};

// explicatory only - we could do without this specialisation
template<class T>
struct RemoveRefCond<T&, false> {
  typedef T& Type;
};

} // namespace Cgu

#endif // CGU_PARAM_H
