// bslmf_removeextent.h                                               -*-C++-*-
#ifndef INCLUDED_BSLMF_REMOVEEXTENT
#define INCLUDED_BSLMF_REMOVEEXTENT

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

//@PURPOSE: Provide a metafunction to return an array type's element type.
//
//@CLASSES:
//  bsl::remove_extent: type trait that returns the element type of an array
//  bsl::remove_extent_t: alias to the return type of the `bsl::remove_extent`
//
//@SEE_ALSO: bslmf_decay
//
//@DESCRIPTION: This component provides a metafunction `bsl::remove_extent`
// that returns the element type of an array.  The functionality is intended to
// be identical to the C++11 metafunction `std::remove_extent`.  From the C++14
// standard:
//
// If `T` names a type "array of `U`", the member typedef `type` shall be `U`,
// otherwise `T`.  [ *Note:* For multidimensional arrays, only the first array
// dimension is removed.  For a type "array of `const U`", the resulting type
// is `const U`.  -- *end note* ]
//
///Usage
///-----
// The class template `Traverser` is used to traverse an array and perform some
// operation.  In order to do its job in the case of two-dimensional arrays,
// `Traverser` must hold on to an entire row of the array at a time in order to
// process it correctly.  The row type is determined from the array type using
// `remove_extent`:
// ```
// template <class ARRAY_TYPE>
// class Traverser {
//   public:
//
// #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
// ```
// Note that if the current compiler supports alias templates C++11 feature, we
// can use `bsl::remove_extent_t` alias to the "result" type of the
// `bsl::remove_extent` meta-function, that avoids the `::type` suffix and
// `typename` prefix in the declaration of the function return type:
// ```
//     using RowType = bsl::remove_extent_t<ARRAY_TYPE>;
// #else
//     typedef typename bsl::remove_extent<ARRAY_TYPE>::type RowType;
// #endif
//
//   private:
//     RowType d_row;  // Might be scalar
//     // ...
//
//     // CREATORS
//     Traverser() : d_row() {}
// };
// ```
// Now we can see that the row type is the type of the array after having
// striped off the high-order dimension:
// ```
// int main()
// {
//     assert((bsl::is_same<int, Traverser<int>::RowType>::value));
//     assert((bsl::is_same<int, Traverser<int[]>::RowType>::value));
//     assert((bsl::is_same<int, Traverser<int[5]>::RowType>::value));
//     typedef const int MyRow[6];
//     assert((bsl::is_same<MyRow, Traverser<MyRow[]>::RowType>::value));
//     assert((bsl::is_same<int[6], Traverser<int[7][6]>::RowType>::value));
//
//     return 0;
// }
// ```

#include <bslscm_version.h>

#include <bsls_compilerfeatures.h>

#include <cstddef>

namespace bsl {

                        // ============================
                        // class template remove_extent
                        // ============================

/// From the C++14 standard: If `T` names a type "array of `U`", the member
/// typedef `type` shall be `U`, otherwise `T`.  [ *Note:* For
/// multidimensional arrays, only the first array dimension is removed.  For
/// a type "array of `const U`", the resulting type is `const U`.  -- *end
/// note* ]
template <class t_TYPE>
struct remove_extent {

    typedef t_TYPE type;
};

/// Specialization of `remove_extent` for array of unknown bound
template <class t_TYPE>
struct remove_extent<t_TYPE[]> {

    typedef t_TYPE type;
};

/// Specialization of `remove_extent` for array of known bound
template <class t_TYPE, std::size_t t_SZ>
struct remove_extent<t_TYPE[t_SZ]> {

    typedef t_TYPE type;
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

// ALIASES

/// `remove_extent_t` is an alias to the return type of the
/// `bsl::remove_extent` meta-function.  Note, that the `enable_if_t` avoids
/// the `::type` suffix and `typename` prefix when we want to use the result
/// of the meta-function in templates.
template <class t_TYPE>
using remove_extent_t = typename remove_extent<t_TYPE>::type;

#endif  // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

}  // close namespace bsl

#endif // ! defined(INCLUDED_BSLMF_REMOVEEXTENT)

// ----------------------------------------------------------------------------
// Copyright 2019 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 ----------------------------------
