// bslmf_isreferencewrapper.h                                         -*-C++-*-
#ifndef INCLUDED_BSLMF_ISREFERENCEWRAPPER
#define INCLUDED_BSLMF_ISREFERENCEWRAPPER

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a trait to detect reference-wrapper specializations.
//
//@CLASSES:
//  bslmf::IsReferenceWrapper: metafunction for detecting reference wrappers
//
//@SEE_ALSO: bslstl_referencewrapper
//
//@DESCRIPTION: This component provides a 'struct' template,
// 'bslmf::IsReferenceWrapper', that is a boolean metafunction with a single
// class template parameter 't_TYPE'.  'bslmf::IsReferenceWrapper' derives from
// 'bsl::false_type' by default.  The only intended specialization of
// 'bslmf::IsReferenceWrapper' is for 'bsl::reference_wrapper'.  Clients are
// not allowed to specialized 'bslmf::IsReferenceWrapper' for any other type.
//
// This component exists primarily because there are other type traits provided
// by components in the 'bslmf' package that require the ability to detect
// whether or not a type is a specialization of 'bsl::reference_wrapper',
// notably 'bsl::invoke_result'.  'bsl::reference_wrapper' is defined in the
// 'bslstl_referencewrapper' component in the 'bslstl' package, and is
// available to clients through the 'bsl_functional' component in the
// 'bsl+bslhdrs' package.  These packages are levelized above 'bslmf', and so
// this trait permits components in the 'bslmf' package (and above) to detect
// whether or not a type is a reference wrapper even if they cannot refer to
// the 'bsl::reference_wrapper' type.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example: Reference Access
///- - - - - - - - - - - - -
// In this example, we suppose that we would like to provide a software
// component that treats specializations of 'bsl::reference_wrapper' and
// true reference qualified types in the same way.
//
// Suppose that we would like to do this by having a utility function that
// returns an lvalue reference to an object given either an lvalue-reference
// qualified type or a 'bsl::reference_wrapper'.
//
// First, we define a utility 'struct' that contains the overload of this
// utility function for 'const' and non-'const' lvalue-reference qualified
// types:
//..
//  struct MyLvalueReferenceUtil {
//      // CLASS METHODS
//      template <class t_TYPE>
//      static t_TYPE& access(t_TYPE& reference)
//      {
//          return reference;
//      }
//
//      template <class t_TYPE>
//      static const t_TYPE& access(const t_TYPE& reference)
//      {
//          return reference;
//      }
//..
// Then, we define the overload of this utility function for reference
// wrappers, taking care to define it such that it does not participate in
// overload resolution unless it is passed a reference wrapper:
//..
//      template <class t_TYPE>
//      static typename bsl::enable_if<
//          bslmf::IsReferenceWrapper<t_TYPE>::value,
//          typename bsl::add_lvalue_reference<typename t_TYPE::type>::type
//      >::type
//      access(t_TYPE referenceWrapper)
//      {
//          return referenceWrapper.get();
//      }
//  };
//..
// Finally, we can verify that this utility allows us to transparently access
// lvalue references:
//..
//  void example()
//  {
//      int x = 1;
//      assert(1 == MyLvalueReferenceUtil::access(x));
//
//      const int y = 2;
//      assert(2 == MyLvalueReferenceUtil::access(y));
//
//      // Note that even though the following invokes 'access' with the
//      // literal 3, which is a prvalue expression, the call expression is
//      // an lvalue with type 'const int&'.
//      assert(3 == MyLvalueReferenceUtil::access(3));
//
//      // Further, note that the levelization of the
//      // 'bslmf_isreferencewrapper' component prohibits showing the
//      // application of 'MyLvalueReferenceUtil' to a reference wrapper.
//      // The following commented-out code would be valid given a suitable
//      // 'bsl::reference_wrapper' type that acts like a reference wrapper
//      // and specializes the 'bslmf::IsReferenceWrapper' trait accordingly.
//      //..
//      //  assert(x == MyLvalueReferenceUtil::access(
//      //                                    bsl::reference_wrapper<int>(x)));
//      //..
//  }
//..

#include <bslmf_integralconstant.h>

namespace BloombergLP {
namespace bslmf {

                         // =========================
                         // struct IsReferenceWrapper
                         // =========================

template <class t_TYPE>
struct IsReferenceWrapper : bsl::false_type {
    // This 'struct' template implements a boolean metafunction used to detect
    // if the specified 't_TYPE' is a reference wrapper.  Clients may
    // specialize this 'struct' template to inherit from 'bsl::true_type' for
    // 't_TYPE' types that are specializations of 'bsl::reference_wrapper'.
    // The behavior is undefined if any other specialization of this 'struct'
    // template is defined.  Note that this 'struct' template
};

}  // close enterprise namespace
}  // close package namespace

#endif // INCLUDED_BSLMF_ISREFERENCEWRAPPER

// ----------------------------------------------------------------------------
// Copyright 2021 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------