// bslmf_enableif.h                                                   -*-C++-*-
#ifndef INCLUDED_BSLMF_ENABLEIF
#define INCLUDED_BSLMF_ENABLEIF

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

//@PURPOSE: Provide a utility to set up SFINAE conditions in type deduction.
//
//@CLASSES:
//  bsl::enable_if: standard meta-function to drop templates from overload sets
//  bsl::enable_if_t: alias to the return type of the meta-function
//  bslmf::EnableIf: meta-function to drop templates from overload sets
//
//@DESCRIPTION: This component defines two meta-functions, `bsl::enable_if` and
// `bslmf::EnableIf`, both of which may be used to conditionally remove
// (potential) template instantiations as candidates for overload resolution by
// causing a deduced template instantiation to fail in a way compatible with
// the C++ SFINAE rules.
//
// `bsl::enable_if` meets the requirements of the `enable_if` template defined
// in the C++11 standard [meta.trans.ptr], while `bslmf::EnableIf` was devised
// before `enable_if` was standardized.
//
// The two meta-functions provide identical functionality.  Both meta-functions
// provide a `typedef` `type` that is an alias to a (template parameter) type
// if a (template parameter) condition is `true`; otherwise, `type` is not
// provided.
//
// Note that `bsl::enable_if` should be preferred over `bslmf::EnableIf`, and
// in general, should be used by new components.
//
///Visual Studio Workaround
///------------------------
// Because of a Visual Studio bug, described here:
//   http://connect.microsoft.com/VisualStudio/feedback/details/332179/
// the Microsoft Visual Studio compiler may not correctly associate a function
// declaration that uses `bsl::enable_if` with that function's definition, if
// the definition is not inline to the declaration.  This bug affects at least
// Visual Studio 2008 and 2010.  The workaround is to implement functions using
// `bsl::enable_if` inline with their declaration.
//
///Usage
///-----
// The following snippets of code illustrate basic use of the `bsl::enable_if`
// meta-function.  We will demonstrate how to use this utility to control
// overload sets with three increasingly complex examples.
//
///Example 1: Implementing a Simple Function with `bsl::enable_if`
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose that we want to implement a simple `swap` function template to
// exchange two arbitrary values, as if defined below:
// ```
// template<class t_TYPE>
// void DummySwap(t_TYPE& a, t_TYPE& b)
//     // Exchange the values of the specified objects, 'a' and 'b'.
// {
//     t_TYPE temp(a);
//     a = b;
//     b = temp;
// }
// ```
// However, we want to take advantage of member-swap methods supplied by user-
// defined types, so we define a trait that can be customized by a class
// implementer to indicate that their class supports an optimized member-swap
// method:
// ```
// template<class t_TYPE>
// struct HasMemberSwap : bsl::false_type {
//     // This traits class indicates whether the (template parameter)
//     // 't_TYPE' has a public 'swap' method to exchange values.
// };
// ```
// Now, we implement a generic `swap` function template that will invoke the
// member swap operation for any type that specialized our trait.  The use of
// `bsl::enable_if` to declare the result type causes an attempt to deduce the
// type `t_TYPE` to fail unless the specified condition is `true`, and this
// falls under the "Substitution Failure Is Not An Error" (SFINAE) clause of
// the C++ standard, so the compiler will look for a more suitable overload
// rather than fail with an error.  Note that we provide two overloaded
// declarations that appear to differ only in their return type, which would
// normally raise an ambiguity error.  This works, and is in fact required, in
// this case as the "enable-if" conditions are mutually exclusive, so that only
// one overload will ever be present in an overload set.  Also note that the
// `type` `typedef` of `bsl::enable_if` is an alias to `void` when the
// (template parameter) type is unspecified and the (template parameter)
// condition value is `true`.
// ```
// template<class t_TYPE>
// typename bsl::enable_if<HasMemberSwap<t_TYPE>::value>::type
// swap(t_TYPE& a, t_TYPE& b)
// {
//     a.swap(b);
// }
//
// template<class t_TYPE>
// typename bsl::enable_if< ! HasMemberSwap<t_TYPE>::value>::type
// swap(t_TYPE& a, t_TYPE& b)
// {
//     t_TYPE temp(a);
//     a = b;
//     b = temp;
// }
// ```
// Next, we define a simple container template, that supports an optimized
// `swap` operation by merely swapping the internal pointer to the array of
// elements rather than exchanging each element:
// ```
// template<class t_TYPE>
// class MyContainer {
//     // This is a simple container implementation for demonstration purposes
//     // that is modeled after 'std::vector'.
//
//     // DATA
//     t_TYPE *d_storage;
//     size_t  d_length;
//
//     // Copy operations are declared private and not defined.
//
//     // NOT IMPLEMENTED
//     MyContainer(const MyContainer&);
//     MyContainer& operator=(const MyContainer&);
//
//   public:
//     MyContainer(const t_TYPE& value, int n);
//         // Create a 'MyContainer' object having the specified 'n' copies of
//         // the specified 'value'.  The behavior is undefined unless
//         // '0 <= n'.
//
//     ~MyContainer();
//         // Destroy this container and all of its elements, reclaiming any
//         // allocated memory.
//
//     // MANIPULATORS
//     void swap(MyContainer &other);
//         // Exchange the contents of 'this' container with those of the
//         // specified 'other'.  No memory will be allocated, and no
//         // exceptions are thrown.
//
//     // ACCESSORS
//     const t_TYPE& front() const;
//         // Return a reference providing non-modifiable access to the first
//         // element in this container.  The behavior is undefined if this
//         // container is empty.
//
//     size_t size() const;
//         // Return the number of elements held by this container.
// };
// ```
// Then, we specialize our `HasMemberSwap` trait for this new container type.
// ```
// template<class t_TYPE>
// struct HasMemberSwap<MyContainer<t_TYPE> > : bsl::true_type {
// };
// ```
// Next, we implement the methods of this class:
// ```
// // CREATORS
// template<class t_TYPE>
// MyContainer<t_TYPE>::MyContainer(const t_TYPE& value, int n)
// : d_storage(new t_TYPE[n])
// , d_length(n)
// {
//     for (int i = 0; i != n; ++i) {
//         d_storage[i] = value;
//     }
// }
//
// template<class t_TYPE>
// MyContainer<t_TYPE>::~MyContainer()
// {
//     delete[] d_storage;
// }
//
// // MANIPULATORS
// template<class t_TYPE>
// void MyContainer<t_TYPE>::swap(MyContainer& other)
// {
//     ::swap(d_storage, other.d_storage);
//     ::swap(d_length,  other.d_length);
// }
//
// // ACCESSORS
// template<class t_TYPE>
// const t_TYPE& MyContainer<t_TYPE>::front() const
// {
//     return d_storage[0];
// }
//
// template<class t_TYPE>
// size_t MyContainer<t_TYPE>::size() const
// {
//     return d_length;
// }
// ```
// Finally, we can test that the member-`swap` method is called by the generic
// `swap` function.  Note that the following code will not compile unless the
// member-function `swap` is used, as the copy constructor and assignment
// operator for the `MyContainer` class template are declared as `private`.
// ```
// void TestSwap()
// {
//     MyContainer<int> x(3, 14);
//     MyContainer<int> y(2, 78);
//     assert(14 == x.size());
//     assert( 3 == x.front());
//     assert(78 == y.size());
//     assert( 2 == y.front());
//
//     swap(x, y);
//
//     assert(78 == x.size());
//     assert( 2 == x.front());
//     assert(14 == y.size());
//     assert( 3 == y.front());
// }
// ```
//
///Example 2: Using the `bsl::enable_if` Result Type
///- - - - - - - - - - - - - - - - - - - - - - - - -
// For the next example, we will demonstrate the use of the second template
// parameter in the `bsl::enable_if` template, which serves as the "result"
// type if the test condition passes.  Suppose that we want to write a generic
// function to allow us to cast between pointers of different types.  If the
// types are polymorphic, we can use `dynamic_cast` to potentially cast between
// two seemingly unrelated types.  However, if either type is not polymorphic
// then the attempt to use `dynamic_cast` would be a compile-time failure, and
// we must use `static_cast` instead.
// ```
// #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
// ```
// Note that if the current compiler supports alias templates C++11 feature, we
// can use `bsl::enable_if_t` alias to the "result" type of `bsl::enable_if`
// meta-function, that avoids the `::type` suffix and `typename` prefix in the
// declaration of the function return type.
// ```
// template<class t_TO, class t_FROM>
// bsl::enable_if_t<bsl::is_polymorphic<t_FROM>::value &&
//                  bsl::is_polymorphic<t_TO  >::value, t_TO> *
// #else
// template<class t_TO, class t_FROM>
// typename bsl::enable_if<bsl::is_polymorphic<t_FROM>::value &&
//                                           bsl::is_polymorphic<t_TO>::value,
//                         t_TO>::type *
// #endif
// smart_cast(t_FROM *from)
//     // Return a pointer to the specified 'TO' type if the specified 'from'
//     // pointer refers to an object whose complete class publicly derives,
//     // directly or indirectly, from 'TO', and a null pointer otherwise.
// {
//     return dynamic_cast<t_TO *>(from);
// }
//
// #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
// template<class t_TO, class t_FROM>
// bsl::enable_if_t<not(bsl::is_polymorphic<t_FROM>::value &&
//                      bsl::is_polymorphic<t_TO  >::value), t_TO> *
// #else
// template<class t_TO, class t_FROM>
// typename bsl::enable_if<not(bsl::is_polymorphic<t_FROM>::value &&
//                                          bsl::is_polymorphic<t_TO>::value),
//                         t_TO>::type *
// #endif
// smart_cast(t_FROM *from)
//     // Return the specified 'from' pointer value cast as a pointer to type
//     // 'TO'.  The behavior is undefined unless such a conversion is valid.
// {
//     return static_cast<t_TO *>(from);
// }
// ```
// Next, we define a small number of classes to demonstrate that this casting
// utility works correctly:
// ```
// class A {
//     // Sample non-polymorphic type
//
//   public:
//     ~A() {}
// };
//
// class B {
//     // Sample polymorphic base-type
//
//   public:
//     virtual ~B() {}
// };
//
// class C {
//     // Sample polymorphic base-type
//
//   public:
//     virtual ~C() {}
// };
//
// class ABC : public A, public B, public C {
//     // Most-derived example class using multiple bases in order to
//     // demonstrate cross-casting.
// };
// ```
// Finally, we demonstrate the correct behavior of the `smart_cast` utility:
// ```
// void TestSmartCast()
// {
//     ABC  object;
//     ABC *pABC = &object;
//     A   *pA   = &object;
//     B   *pB   = &object;
//     C   *pC   = &object;
//
//     A *pA2 = smart_cast<A>(pABC);
//     B *pB2 = smart_cast<B>(pC);
//     C *pC2 = smart_cast<C>(pB);
//
//     (void) pA;
//
//     assert(&object == pA2);
//     assert(&object == pB2);
//     assert(&object == pC2);
//
//     // These lines would fail to compile
//     // A *pA3 = smart_cast<A>(pB);
//     // C *pC3 = smart_cast<C>(pA);
// }
// ```
//
///Example 3: Controlling Constructor Selection with `bsl::enable_if`
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The final example demonstrates controlling the selection of a constructor
// template in a class with (potentially) many constructors.  We define a
// simple container template based on `std::vector` that illustrates a problem
// that may occur when trying to call the constructor the user expects.  For
// this example, assume we are trying to create a `vector<int>` with `42`
// copies of the value `13`.  When we pass the literal values `42` and `13` to
// the compiler, the "best" candidate constructor should be the template
// constructor that takes two arguments of the same kind, deducing that type to
// be `int`.  Unfortunately, that constructor expects those values to be of an
// iterator type, forming a valid range.  We need to avoid calling this
// constructor unless the deduced type really is an iterator, otherwise a
// compile-error will occur trying to instantiate that constructor with an
// incompatible argument type.  We use `bsl::enable_if` to create a deduction
// context where SFINAE can kick in.  Note that we cannot deduce the `::type`
// result of a meta-function, and there is no result type (as with a regular
// function) to decorate, so we add an extra dummy argument using a pointer
// type (produced from `bsl::enable_if::type`) with a default null argument:
// ```
// template<class t_TYPE>
// class MyVector {
//     // This is a simple container implementation for demonstration purposes
//     // that is modeled after 'std::vector'.
//
//     // DATA
//     t_TYPE  *d_storage;
//     size_t   d_length;
//
//     // NOT IMPLEMENTED
//     MyVector(const MyVector&);
//     MyVector& operator=(const MyVector&);
//
//   public:
//     // CREATORS
//     MyVector(const t_TYPE& value, int n);
//         // Create a 'MyVector' object having the specified 'n' copies of
//         // the specified 'value'.  The behavior is undefined unless
//         // '0 <= n'.
//
//     template<class t_FORWARD_ITERATOR>
//     MyVector(t_FORWARD_ITERATOR first, t_FORWARD_ITERATOR last,
//                 typename bsl::enable_if<
//                    bsl::is_pointer<t_FORWARD_ITERATOR>::value>::type * = 0)
//         // Create a 'MyVector' object having the same sequence of values as
//         // found in the range described by the specified iterators
//         // '[first, last)'.  The behavior is undefined unless 'first' and
//         // 'last' refer to a sequence of values of the (template parameter)
//         // type 't_TYPE' where 'first' is at a position at or before
//         // 'last'.  Note that this function is currently defined inline to
//         // work around an issue with the Microsoft Visual Studio compiler.
//     {
//         d_length = 0;
//         for (t_FORWARD_ITERATOR cursor = first; cursor != last; ++cursor) {
//              ++d_length;
//         }
//
//         d_storage = new t_TYPE[d_length];
//         for (size_t i = 0; i != d_length; ++i) {
//              d_storage[i] = *first;
//              ++first;
//         }
//     }
//
//     ~MyVector();
//         // Destroy this container and all of its elements, reclaiming any
//         // allocated memory.
//
//     // ACCESSORS
//     const t_TYPE& operator[](int index) const;
//         // Return a reference providing non-modifiable access to the
//         // element held by this container at the specified 'index'.  The
//         // behavior is undefined unless 'index < size()'.
//
//     size_t size() const;
//         // Return the number of elements held by this container.
// };
// ```
// Note that there is no easy test for whether a type is an iterator, so we
// assume that any attempt to call a constructor with two arguments that are
// not fundamental (such as `int`) must be passing iterators.  Now that we have
// defined the class template, we implement its methods:
// ```
// template<class t_TYPE>
// MyVector<t_TYPE>::MyVector(const t_TYPE& value, int n)
// : d_storage(new t_TYPE[n])
// , d_length(n)
// {
//     for (int i = 0; i != n; ++i) {
//         d_storage[i] = value;
//     }
// }
//
// template<class t_TYPE>
// MyVector<t_TYPE>::~MyVector()
// {
//     delete[] d_storage;
// }
//
// // ACCESSORS
// template<class t_TYPE>
// const t_TYPE& MyVector<t_TYPE>::operator[](int index) const
// {
//     return d_storage[index];
// }
//
// template<class t_TYPE>
// size_t MyVector<t_TYPE>::size() const
// {
//     return d_length;
// }
// ```
// Finally, we demonstrate that the correct constructors are called when
// invoked with appropriate arguments:
// ```
// void TestContainerConstructor()
// {
//     const unsigned int TEST_DATA[] = { 1, 2, 3, 4, 5 };
//
//     const MyVector<unsigned int> x(&TEST_DATA[0], &TEST_DATA[5]);
//     const MyVector<unsigned int> y(13, 42);
//
//     assert(5 == x.size());
//     for (int i = 0; i != 5; ++i) {
//         assert(TEST_DATA[i] == x[i]);
//     }
//
//     assert(42 == y.size());
//     for (int i = 0; i != 42; ++i) {
//         assert(13 == y[i]);
//     }
// }
// ```

#include <bslscm_version.h>

#include <bsls_compilerfeatures.h>

namespace bsl {

                         // ================
                         // struct enable_if
                         // ================

/// This `struct` template implements the `enable_if` meta-function defined
/// in the C++11 standard [meta.trans.ptr].  This `struct` template provides
/// a `typedef` `type` that is an alias to the (template parameter) `t_TYPE`
/// if the (template parameter) `t_COND` is `true`; otherwise, `type` is not
/// provided.  If `t_TYPE` is not specified, it is set to `void`.  Note that
/// this generic default template provides `type` for when `t_COND` is
/// `true`; a template specialization is provided (below) that omits `type`
/// for when `t_COND` is `false`.
template <bool t_COND, class t_TYPE = void>
struct enable_if {

    /// This `typedef` is an alias to the (template parameter) `t_TYPE`.
    typedef t_TYPE type;
};

                      // ===============================
                      // struct enable_if<false, t_TYPE>
                      // ===============================

/// This partial specialization of `enable_if`, for when the (template
/// parameter) `t_COND` is `false`, guarantees that no `typedef` `type` is
/// supplied.  Note that this class definition is intentionally empty.
template <class t_TYPE>
struct enable_if<false, t_TYPE> {
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

// ALIASES

/// `enable_if_t` is an alias to the return type of the `bsl::enable_if`
/// 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 <bool t_COND, class t_TYPE = void>
using enable_if_t = typename enable_if<t_COND, t_TYPE>::type;

#endif  // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

}  // close namespace bsl

namespace BloombergLP {

namespace bslmf {

                               // ===============
                               // struct EnableIf
                               // ===============

/// This `struct` template implements a meta-function that provides a
/// `typedef` `type` that is an alias to the (template parameter) `t_TYPE`
/// if the (template parameter) `t_COND` is `true`; otherwise, `type` is not
/// provided.  If `t_TYPE` is not specified, it is set to `void`.  Note that
/// this generic default template provides `type` for when `t_COND` is
/// `true`; a template specialization is provided (below) that omits `type`
/// for when `t_COND` is `false`.
///
/// Also note that although this `struct` is functionally identical to
/// `bsl::enable_if`, the use of `bsl::enable_if` should be preferred.
template <bool t_COND, class t_TYPE = void>
struct EnableIf {

    /// This `typedef` is an alias to the (template parameter) `t_TYPE`.
    typedef t_TYPE type;
};

/// This partial specialization of `EnableIf`, for when the (template
/// parameter) `t_COND` is `false`, guarantees that no `typedef` `type` is
/// supplied.  Note that this class definition is intentionally empty.
template <class t_TYPE>
struct EnableIf<false, t_TYPE> {
};

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

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#ifdef bslmf_EnableIf
#undef bslmf_EnableIf
#endif
/// This alias is defined for backward compatibility.
#define bslmf_EnableIf bslmf::EnableIf
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

#endif

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