// bsls_unspecifiedbool.h                                             -*-C++-*-
#ifndef INCLUDED_BSLS_UNSPECIFIEDBOOL
#define INCLUDED_BSLS_UNSPECIFIEDBOOL

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

//@PURPOSE: Provide a class supporting the 'unspecified bool' idiom.
//
//@CLASSES:
//  bsls::UnspecifiedBool: class template for the 'unspecified bool' idiom.
//
//@DESCRIPTION: This component provides a class template that can be used to
// manufacture an "unspecified boolean type" that is distinct for each class
// that instantiates it.  Note that classes supplying an implicit conversion to
// an unspecified bool type will be equality comparable (using 'operator==' and
// 'operator!=') through this conversion.  Private equality and inequality
// operators should be added to the class definition unless this comparison is
// desired.  It is important that each class produces a distinct unspecified
// bool type, as otherwise objects of different class types would compare equal
// through this same conversion.
//
///Relationship to C++11
///---------------------
// This component will become redundant when all Bloomberg production compilers
// support "explicit conversion operators", a feature of C++11.  An
// 'explicit operator bool()' conversion operator is superior to this C++98
// idiom in all ways.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: A Simple Smart Pointer
///- - - - - - - - - - - - - - - - -
// A common requirement for "smart pointer" types is to emulate the native
// pointer types and, in particular, support testing for "null" or "empty"
// pointer values as a simple boolean conversion in 'if' and 'while' clauses.
// We here demonstrate how to create a simple smart pointer type, 'SimplePtr',
// using this component to implement a safe the boolean conversion.
//
// An object of type 'SimplePtr' holds a pointer value, but does not claim
// ownership or any responsibility for the lifetime of the referenced object.
// A 'SimplePtr' object acts as a "simple" native pointer.
//
// First, we create the 'SimplePtr' class, define its data members, creators
// and manipulators:
//..
//  template <class TYPE>
//  class SimplePtr
//  {
//      // This class holds a pointer to a single object, and provides a subset
//      // of the regular pointer operators.  For example, objects of this
//      // class can be dereferenced with 'operator*' and tested as a boolean
//      // value to determine if null.  Conversely, this class does not support
//      // pointer arithmetic.
//
//    private:
//      // DATA
//      TYPE *d_ptr_p;  // address of the referenced object
//
//      // PRIVATE ACCESSORS
//      bool operator==(const SimplePtr &);  // = delete;
//      bool operator!=(const SimplePtr &);  // = delete;
//          // Suppress equality-comparison operations on objects of this
//          // class.
//
//    public:
//      // CREATORS
//      explicit SimplePtr(TYPE *ptr = 0) : d_ptr_p(ptr) {}
//          // Create a 'SimplePtr' having the value of the specified 'ptr'.
//
//      //! ~SimplePtr() = default;
//          // Destroy this object.
//
//      // ACCESSORS
//      TYPE& operator*() const  { return *d_ptr_p; }
//          // Return a reference to the object pointed to by this
//          // 'SimplePtr'.
//
//      TYPE *operator->() const { return d_ptr_p; }
//          // Return the held 'd_ptr_p'.
//..
// Next, we define, for convenience, an alias for a unique type that is
// implicitly convertible to 'bool' (note that we pass the current template
// instantiation to the 'bsls::UnspecifiedBool' template to guarantee a unique
// name, even for different instantiations of this same 'SimplePtr' template):
//..
//  // TYPES
//  typedef typename bsls::UnspecifiedBool<SimplePtr>::BoolType BoolType;
//..
// Now, we can define a boolean conversion operator that tests whether or not
// this 'SimplePtr' object is holding a null pointer, or a valid address:
//..
//      operator BoolType() const {
//          return bsls::UnspecifiedBool<SimplePtr>::makeValue(d_ptr_p);
//      }
//  }; // class SimplePtr
//..
// Note that we do not need to define 'operator!' as this single boolean
// conversion operator is invoked with the correct semantics when the user
// tries that operator.
//
// Finally, we write a simple test function, creating a couple of 'SimplePtr'
// objects, one "null", and the other with a well-defined address.
//..
//  void runTests() {
//      SimplePtr<int> p1;  // default ctor sets to null
//      assert(!p1);
//
//      int            i = 3;
//      SimplePtr<int> p2(&i);
//
//      if (p2) {
//          assert(3 == *p2);
//      }
//  }
//..
// Notice that 'SimplePtr' objects behave as native pointers.  They should be
// tested before dereferencing (as they could be null).

namespace BloombergLP {

namespace bsls {

                         // =====================
                         // class UnspecifiedBool
                         // =====================

template<class BSLS_HOST_TYPE>
class UnspecifiedBool {
    // This class provides a member, 'd_member', whose pointer-to-member may be
    // used as an "unspecified boolean type" for implicit conversion operators.

  private:
    // DATA
    int d_member;   // This data member is used solely for taking its address
                    // to return a non-null pointer-to-member.  Note that the
                    // *value* of 'd_member' is not used.

  public:
    // TYPES
    typedef int UnspecifiedBool::* BoolType;
        // Alias of a distinct type that is implicitly convertible to 'bool',
        // but does not promote to 'int'.

    // CLASS METHODS
    static BoolType falseValue();
        // Return a value that converts to the 'bool' value 'false'.

    static BoolType trueValue();
        // Return a value that converts to the 'bool' value 'true'.

    static BoolType makeValue(bool predicate);
        // Return a value that converts to the 'bool' value 'true' if the
        // specified predicate is 'true', and the 'bool' value 'false'
        // otherwise.
};


// ============================================================================
//                        INLINE FUNCTION DEFINITIONS
// ============================================================================

// CLASS METHODS
template<class BSLS_HOST_TYPE>
inline
typename UnspecifiedBool<BSLS_HOST_TYPE>::BoolType
UnspecifiedBool<BSLS_HOST_TYPE>::falseValue()
{
    return 0;
}

template<class BSLS_HOST_TYPE>
inline
typename UnspecifiedBool<BSLS_HOST_TYPE>::BoolType
UnspecifiedBool<BSLS_HOST_TYPE>::trueValue()
{
    return &UnspecifiedBool::d_member;
}

template<class BSLS_HOST_TYPE>
inline
typename UnspecifiedBool<BSLS_HOST_TYPE>::BoolType
UnspecifiedBool<BSLS_HOST_TYPE>::makeValue(bool predicate)
{
    return predicate ? trueValue() : falseValue();
}

}  // close package namespace

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

#ifdef bsls_UnspecifiedBool
#undef bsls_UnspecifiedBool
#endif
#define bsls_UnspecifiedBool bsls::UnspecifiedBool
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // close enterprise namespace

#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 ----------------------------------