// 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 TO, class FROM>
//  typename bsl::enable_if<bsl::is_polymorphic<FROM>::value &&
//                                              bsl::is_polymorphic<TO>::value,
//                          TO>::type *
//#else
//  template<class TO, class FROM>
//  bsl::enable_if_t<bsl::is_polymorphic<FROM>::value &&
//                      bsl::is_polymorphic<TO  >::value, TO> *
//#endif
//  smart_cast(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<TO *>(from);
//  }
//
//#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
//  template<class TO, class FROM>
//  bsl::enable_if_t<not(bsl::is_polymorphic<FROM>::value &&
//                       bsl::is_polymorphic<TO  >::value), TO> *
//#else
//  template<class TO, class FROM>
//  typename bsl::enable_if<not(bsl::is_polymorphic<FROM>::value &&
//                                            bsl::is_polymorphic<TO>::value),
//                          TO>::type *
//#endif
//  smart_cast(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<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 FORWARD_ITERATOR>
//      MyVector(FORWARD_ITERATOR first, FORWARD_ITERATOR last,
//                  typename bsl::enable_if<
//                      !bsl::is_fundamental<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 (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
                         // ================

template <bool t_COND, class t_TYPE = void>
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'.

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

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

template <class t_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.
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

// ALIASES
template <bool t_COND, class t_TYPE = void>
using enable_if_t = typename enable_if<t_COND, t_TYPE>::type;
    // '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.

#endif  // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

}  // close namespace bsl

namespace BloombergLP {

namespace bslmf {

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

template <bool t_COND, class t_TYPE = void>
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.

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

template <class t_TYPE>
struct EnableIf<false, t_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.
};

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

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

#ifdef bslmf_EnableIf
#undef bslmf_EnableIf
#endif
#define bslmf_EnableIf bslmf::EnableIf
    // This alias is defined for backward compatibility.
#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 ----------------------------------