// bsltf_evilbooleantype.h                                            -*-C++-*-
#ifndef INCLUDED_BSLTF_EVILBOOLEANTYPE
#define INCLUDED_BSLTF_EVILBOOLEANTYPE

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

//@PURPOSE: Provide the most awkward type that is convertible to `bool`.
//
//@CLASSES:
//  bsltf::EvilBooleanType: most awkward type that is convertible to `bool`
//
//@SEE_ALSO: bsltf_templatetestfacility
//
//@DESCRIPTION: This component provides a type that is convertible-to-`bool`,
// and so may be used to satisfy many C++ standard library requirements, but is
// perversely implemented to provide the most awkward interface that meets the
// requirements.  This type is not intended for use in production code, but is
// most useful when implementing test drivers for generic components that must
// accept predicates, or other expressions, that yield a type that is merely
// convertible to `bool`.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Syntax
///- - - - - - - - - - - -
// The following snippets of code provide a simple illustration of using
// `bsltf::EvilBooleanType`.
//
// First, we create an object `trueValue` and initialize it with the `true`
// value:
// ```
// bsltf::EvilBooleanType trueValue(true);
// ```
// Now, we can use it for if-else conditions or another constructions, that
// require boolen value:
// ```
// if (trueValue) {
//     assert(trueValue);
// }
// ```
// Finally we create another object, having the opposite value, and verify it:
// ```
// bsltf::EvilBooleanType falseValue = !trueValue;
// assert(false == (bool)falseValue);
// ```

#include <bslscm_version.h>

#include <bsls_keyword.h>

namespace BloombergLP {

namespace bsltf {

                            // =====================
                            // class EvilBooleanType
                            // =====================

/// This class provides a test type for predicates returning a type that is
/// convertible-to-bool.  It makes life reasonably difficult by disabling
/// the address-of and comma operators, but deliberately does not overload
/// the `&&` and `||` operators, as we hope the standard will be updated to
/// no longer require such support.  Once C++11 becomes available, this
/// class would use an `explicit operator bool()` conversion operator, and
/// explicitly supply the `==` and `!=` operators, but we use the
/// convertible-to-pointer-to-member idiom in the meantime.  Implicitly
/// defined operations fill out the API as needed.
struct EvilBooleanType {

  private:
    // PRIVATE TYPES

    /// Struct, containing value to be pointed to.
    struct ImpDetail
    {
        int d_member;
    };


    /// Typedef for pointer to the nested class field, that can be converted
    /// to boolean.
    typedef int ImpDetail::* BoolResult;

    // DATA
    BoolResult d_value;  // pointer being converted to boolean value

  private:
    // NOT IMPLEMENTED
    void operator=(const EvilBooleanType&) BSLS_KEYWORD_DELETED;

    void operator&() const BSLS_KEYWORD_DELETED;

    template<class T>
    void operator,(T&) const BSLS_KEYWORD_DELETED;

  public:
    // CREATORS

    /// Create a `EvilBooleanType` object having the attribute value defined
    /// by the specified `value`.
    EvilBooleanType(bool value);                                    // IMPLICIT

#ifdef BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS
    // To avoid warnings about future incompatibility due to the deleted copy
    // assignment operator we declare the copy constructor as implicitly
    // generated.  For consistency the destructor was also placed here and
    // declared to be explicitly generated.

    /// Create a `EvilBooleanType` object having the same value as the
    /// specified `original` object.
    EvilBooleanType(const EvilBooleanType& original) = default;

    /// Destroy this object.
    ~EvilBooleanType() = default;
#endif

    // ACCESSORS

    /// Return the value of this object.
    operator BoolResult() const;

    /// Return the newly created object having the logically negated value
    /// of this object.
    EvilBooleanType operator!() const;
};

/// Return an `EvilBoolanType` value that converts to `true` if the
/// specified `lhs` and `rhs` have the same value, and a value that converts
/// to `false` otherwise. Two `EvilBooleanType` objects have the same value
/// if the values resulting from converting each to `bool` have the same
/// value.
EvilBooleanType operator==(const EvilBooleanType& lhs,
                           const EvilBooleanType& rhs);

/// Return an `EvilBoolanType` value that converts to `true` if the
/// specified `lhs` and `rhs` do not have the same value, and a value that
/// converts to `false` otherwise. Two `EvilBooleanType` objects do not have
/// the same value if the values resulting from converting each to `bool` do
/// not have the same value.
EvilBooleanType operator!=(const EvilBooleanType& lhs,
                           const EvilBooleanType& rhs);

// ============================================================================
//                  INLINE AND TEMPLATE FUNCTION IMPLEMENTATIONS
// ============================================================================

                       // ---------------------
                       // class EvilBooleanType
                       // ---------------------

// CREATORS
inline
EvilBooleanType::EvilBooleanType(bool value)
: d_value(!value ? 0 : &ImpDetail::d_member)
{
}

// ACCESSORS
inline
EvilBooleanType::operator BoolResult() const
{
    return d_value;
}

inline
EvilBooleanType EvilBooleanType::operator!() const
{
    return !d_value;
}

}  // close package namespace

inline
bsltf::EvilBooleanType bsltf::operator==(const EvilBooleanType& lhs,
                                         const EvilBooleanType& rhs)
{
    return static_cast<bool>(lhs) == static_cast<bool>(rhs);
}

inline
bsltf::EvilBooleanType bsltf::operator!=(const EvilBooleanType& lhs,
                                         const EvilBooleanType& rhs)
{
    return static_cast<bool>(lhs) != static_cast<bool>(rhs);
}

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