// 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
                         // =========================

/// 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
template <class t_TYPE>
struct IsReferenceWrapper : bsl::false_type {
};

}  // close package namespace
}  // close enterprise 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 ----------------------------------
