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

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

  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

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

    // CLASS METHODS

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

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

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


// ============================================================================
//                        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
/// This alias is defined for backward compatibility.
#define bsls_UnspecifiedBool bsls::UnspecifiedBool
#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 ----------------------------------
