// 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(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 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 typedef bool unspecified_bool_t; static unspecified_bool_t unspedified_bool_true() { return true; } #elif defined( _MANAGED ) // From 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 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( *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() const \ * { return safe_bool_t(expr); } * }; * @endcode */ template < class Tag > class safe_bool_t : public safe_bool_convertible< safe_bool_t > { 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() const \ { return ::boost::utility::safe_bool_t(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_