CodePaste Logo
New Snippet New Snippet Recent Snippets Recent Snippets My Snippets My Snippets My Favorites Favorites Web Code Search Snippets Search
Sign inor Register
Language: C++

boost/utility/safe_bool.hpp

349 Views   
// Copyright Krzysztof Czainski 2011
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
 
/**
 * @file cz/boost/utility/safe_bool.hpp
 * Introduction by Vladimir Batov:
 * An implicit conversion to bool (operator bool() const) is very much
 * idiomatic and is often deployed in constructs like "if (foo)" and "if (!foo)"
 * (with no explicit op!() defined). However, sadly, implementing "operator bool()"
 * is *wrong* as that conversion kicks in far too often and unexpectedly. Like in
 * "foo == 1", "foo+1", "1+foo" or potentially during lexical_cast<string>(foo)
 * (if there are no op>>() and op<<() defined). Consequently, that "implicit
 * conversion to bool" functionality has to be implemented in an indirect and
 * somewhat awkward way via an implicit conversion to some other type. The best
 * type for the purpose appears to be a pointer to a member variable. For more
 * see the chapter 7.7 in Alexandrescu's "Modern C++ Design" and the article at 
 * http://www.artima.com/cppsource/safebool.html by Bjorn Karlsson.
 *
 * @warning by Stephan T. Lavavej: Having done this in the STL, I can offer the following
 *  warning: you'll need to generate a different fake-bool type for every class, otherwise things
 *  will be [in]equality comparable that should not be.
 *
 * @since 31-05-2011
 * @author Krzysztof Czainski
 */
 
#ifndef HPP_CZBOOSTUTILITY_SAFE_BOOL_
#define HPP_CZBOOSTUTILITY_SAFE_BOOL_
 
#include "./empty_base.hpp"
 
#include <boost/detail/workaround.hpp>
 
namespace boost { namespace utility {
 
struct as_bool_policy_operator_not
{
    template < class T >
    static bool as_bool( T const& x )
    {
        return ! ! x;
    }
};
 
/**
 * CRTP class, that provides a safe-conversion-to-bool operator, implemented in terms of
 * Derived::operator!
 *
 * @tparam Derived the derived class
 * @tparam Babe a public base class for base class chaining
 *
 * Usage: @see safe_bool_t
 */
template < class Derived, class Base = empty_t, class AsBoolPolicy = as_bool_policy_operator_not >
class safe_bool_convertible : public Base
{
 
#if ( defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, < 0x570) ) \
    || defined(__CINT__)
    // From <boost/smart_ptr/detail/operator_bool.hpp>
 
    typedef bool unspecified_bool_t;
 
    static unspecified_bool_t unspedified_bool_true()
    {
        return true;
    }
 
#elif defined( _MANAGED )
    // From <boost/smart_ptr/detail/operator_bool.hpp>
 
    static void unspecified_bool_true_( Derived*** )
    {}
 
    typedef void (*unspecified_bool_t)( Derived*** );
 
    static unspecified_bool_t unspecified_bool_true()
    {
        return unspecified_bool_true_;
    }
 
#elif ( defined(__MWERKS__) && BOOST_WORKAROUND(__MWERKS__, < 0x3200) ) || \
    ( defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 304) ) || \
    ( defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590) )
    // From <boost/smart_ptr/detail/operator_bool.hpp>
 
    void unspecified_bool_true_() const
    {    }
 
    typedef void (safe_bool_convertible::*unspecified_bool_t)() const;
 
    static unspecified_bool_t unspecified_bool_true()
    {
        return &safe_bool_convertible::unspedified_bool_true_;
    }
 
#else
 
    /*
     * A pointer to members of unspecified_bool_t_struct will be the unspecified_bool_t
     */
    struct unspecified_bool_t_struct
    {
        /**
         * Jeffrey Lee Hellrung, Jr.:
         * According to Andrey Semashev, you do need two data members, as some compilers
         * interpret a pointer-to-first-member as equal to 0 (i.e., convertible to false).
         */
        Derived* dummy;
 
        /**
         * A pointer to @c true_ will be the value @c true for unspecified_bool_t
         */
        Derived* true_;
    };
 
    typedef Derived* unspecified_bool_t_struct::*unspecified_bool_t;
 
    static unspecified_bool_t unspecified_bool_true()
    {
        return &unspecified_bool_t_struct::true_;
    }
 
#endif
 
public:
 
    operator unspecified_bool_t() const
    {
        return AsBoolPolicy::as_bool( static_cast<Derived const&>( *this ) ) ? unspecified_bool_true() : 0;
    }
 
};
 
/**
 * Safe_bool_t is a stand-alone type safely convertible to bool.
 *
 * @note Safe_bool_t is implemented in terms of safe-bool_convertible.
 *
 * Usage:
 * @code
 * struct X
 * {
 *   bool i_am_ok() const;
 *   operator safe_bool_t<X>() const \
 *   { return safe_bool_t<X>(expr); }
 * };
 * @endcode
 */
template < class Tag >
class safe_bool_t : public safe_bool_convertible< safe_bool_t<Tag> >
{
public:
 
    explicit safe_bool_t( bool value = false ) : value_(value)
    {}
 
    bool operator!() const
    {
        return ! value_;
    }
 
private:
 
    bool value_;
};
 
/**
 * Supply implicit conversion to safe_bool_t inside a class.
 *
 * @author Robert Stewart suggested only one macro BOOST_OPERATOR_SAFE_BOOL(expr)
 *
 * @param tag makes the safe_bool type distinct; may be incomplete or the containing class
 * @param expr the boolean expression returned
 *
 * Usage:
 * @code
 * struct X
 * {
 *   bool i_am_ok() const;
 *   BOOST_OPERATOR_SAFE_BOOL_TAGGED( X, i_am_ok() )
 * };
 * @endcode
 */
#define BOOST_OPERATOR_SAFE_BOOL_TAGGED( tag, expr ) \
    operator ::boost::utility::safe_bool_t<tag>() const \
    { return ::boost::utility::safe_bool_t<tag>(expr); }
 
/**
 * Supply implicit conversion to safe_bool_t inside a class.
 *
 * @note Also inserts an incomplete type named safe_bool_tag_ into the class.
 *
 * @author Robert Stewart suggested only one macro BOOST_OPERATOR_SAFE_BOOL(expr)
 *
 * @param expr the boolean expression returned
 *
 * Usage:
 * @code
 * struct X
 * {
 *   bool i_am_ok() const;
 *   BOOST_OPERATOR_SAFE_BOOL( i_am_ok() )
 * };
 * @endcode
 */
#define BOOST_OPERATOR_SAFE_BOOL( expr ) \
    struct safe_bool_tag_; \
    BOOST_OPERATOR_SAFE_BOOL_TAGGED( safe_bool_tag_, expr )
 
/**
 * @def BOOST_EXPLICIT_OPERATOR_BOOL(expr)
 *
 * Supply explicit conversion to bool, if available, or fall back to
 * BOOST_OPERATOR_SAFE_BOOL(expr).
 *
 * @author Jeffrey Lee Hellrung, Jr. has suggested the use of explicit operator bool, if
 *  available.
 *
 * @warning Sebastian Redl:
 * You can only omit the case in "contextual conversion" situations, which are:
 * - Conditions of if, while, do..while and for (maybe switch? not sure);
 * - Arguments to &&, || and !;
 * - First argument to ?:.
 *
 * So these two code examples that a 03 user might write would fail:
 * @code
 * convertible_to_bool obj;
 * bool b = obj; // must write bool b(obj);
 * @endcode
 * @code
 * void fn(bool);
 * fn(obj); // must cast
 * @endcode
 */
 
#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS)
 
#define BOOST_EXPLICIT_OPERATOR_BOOL(expr) \
    BOOST_OPERATOR_SAFE_BOOL(expr)
 
#else // BOOST_NO_EXPLICIT_CONVERSION_OPERATORS
 
#define BOOST_EXPLICIT_OPERATOR_BOOL(expr) \
    explicit operator bool() const \
    { return expr; }
 
#endif // BOOST_NO_EXPLICIT_CONVERSION_OPERATORS
 
}} // boost::utility
 
#endif // HPP_CZBOOSTUTILITY_SAFE_BOOL_
by Krzysztof Czainski
  June 01, 2011 @ 4:29pm
Tags:

Add a comment


Report Abuse
brought to you by:
West Wind Techologies