Safe bool idiom in boost?
I do not know of a commonly accepted utility library that provides the safe-bool idiom. There have been a few attempts within Boost, and they often result in debates about how to provide a safe-bool implementation (naming conventions, macros, inline includes, inheritance). As a result, there are at least three implementations existing within Boost, with only one of the implementations, Boost.Spirit.Classic's safe_bool, designed for external use.
Details and concepts for each implementation:
- Boost.Range's safe_bool
- Contained within the detail directory, so not explicitly designed for external use.
- Implemented by using a template helper type and static member functions.
- The safe-bool enabled class is expected to:
- Provide an
operator boost::range_detail::safe_bool< MemberPtr >::unspecified_bool_type() const
member function that delegates to the staticsafe_bool::to_unspecified_bool()
function.
- Provide an
- Boost.SmartPtr's operator_bool:
- Contained within the detail directory, so not explicitly designed for external use.
- The header file is intended to be included directly within a class definition. See shared_ptr.hpp for an example.
- Requires including
boost/detail/workaround.hpp
before includingsmart_ptr/detail/operator.hpp
. - The surrounding safe-bool enabled class is expected to:
- Provide a
this_type
type. - Provide a
T
type. - Provide a
T* px
member variable.
- Provide a
- Boost.Spirit.Classic's safe_bool
- Designed for external use.
- Uses the CRTP pattern.
- Designed to support base class chaining, allowing
boost::spirit::class::safe_bool
to be used without mandating multiple inheritance on the derived class. - The safe-bool enabled class is expected to:
- Publicly derive from
boost::spirit::classic::safe_bool< Derived >
. IfDerived
already inherits fromBase
, then useboost::spirit::classic::safe_bool< Derived, Base >
. - Provide a
bool operator_bool() const
member function.
- Publicly derive from
This example uses Boost 1.50. Each class should evaluate to true in boolean context if the integer passed to the constructor is greater than 0:
// Safe-bool idiom with Boost.Range.
#include <boost/range/detail/safe_bool.hpp>
class range_bool
{
public:
range_bool( int x ) : x_( x ) {}
private:
// None of these are required, but makes the implementation cleaner.
typedef boost::range_detail::safe_bool< int range_bool::* > safe_bool_t;
typedef safe_bool_t::unspecified_bool_type unspecified_bool_type;
int dummy;
public:
operator unspecified_bool_type() const
{
return safe_bool_t::to_unspecified_bool( x_ > 0, &range_bool::dummy );
}
private:
int x_;
};
// Safe-bool idiom with Boost.SmartPtr.
#include <boost/detail/workaround.hpp>
class smart_ptr_bool
{
public:
smart_ptr_bool( int x ) { px = ( x > 0 ) ? &dummy : 0 ; }
private:
typedef smart_ptr_bool this_type; // -.
typedef int T; // :- Required concepts when using
T* px; // -' smart_ptr's operator_bool.
private:
T dummy; // Simple helper.
public:
#include <boost/smart_ptr/detail/operator_bool.hpp>
};
// Safe-bool idiom with Boost.Spirit.
#include <boost/spirit/include/classic_safe_bool.hpp>
class spirit_bool: public boost::spirit::classic::safe_bool< spirit_bool >
{
public:
spirit_bool( int x ) : x_( x ) {}
public:
// bool operator_bool() is required by the spirit's safe_bool CRTP.
bool operator_bool() const { return x_ > 0; }
private:
int x_;
};
#include <iostream>
int main()
{
std::cout << "range_bool( -1 ): " << range_bool( -1 ) << std::endl
<< "range_bool( 1 ): " << range_bool( 1 ) << std::endl
<< "smart_ptr_bool( -1 ): " << smart_ptr_bool( -1 ) << std::endl
<< "smart_ptr_bool( 1 ): " << smart_ptr_bool( 1 ) << std::endl
<< "spirit_bool( -1 ): " << spirit_bool( -1 ) << std::endl
<< "spirit_bool( 1 ): " << spirit_bool( 1 ) << std::endl;
return 0;
}
Resulting output:
range_bool( -1 ): 0 range_bool( 1 ): 1 smart_ptr_bool( -1 ): 0 smart_ptr_bool( 1 ): 1 spirit_bool( -1 ): 0 spirit_bool( 1 ): 1
I do not know of any alternatives. When I have ran across safe-bool idioms, most of the implementations have been a copy-and-paste variants of the implementation provided in Bjorn Karlsson's article.
Since Boost 1.55 there is <boost/core/explicit_operator_bool.hpp>
header in Boost.Core. It requires from you to define bool operator!()
and use BOOST_EXPLICIT_OPERATOR_BOOL()
macro (there are also variants of it BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
and BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()
).
The documentation has an example:
template< typename T >
class my_ptr
{
T* m_p;
public:
BOOST_EXPLICIT_OPERATOR_BOOL()
bool operator!() const
{
return !m_p;
}
};