Is the Safe-Bool Idiom Obsolete in C++11

Is the safe-bool idiom obsolete in C++11?

Yes. This is the example for problems with only having implicit user-defined conversions and explicit user-defined conversion operators were practically invented because of this problem and to replace all the safe-bool stuff with something a lot cleaner and more logical.

How does the safe bool idiom bool_type (and the safe bool idiom) work?

Your reasoning goes wrong about here

operator void Testable::* () const //Same as bool_type, right? 

This isn't correct. The type of bool_type is, as the compiler tells us in the error message:

'void (Testable::*)()const'

So, to replace it in the operator, you would need something like

operator (void (Testable::*)() const) () const

if that is ever possible! See why even the ugly typedef is an improvement?

In C++11 we also have the new construct explicit operator bool() to save us from this ugliness.

can the safe bool idiom be implemented without having to derive from a safe_bool class?

This should work:

class MyTestableClass
{
private:
void non_comparable_type() {}
public:
typedef void (MyTestableClass::* bool_type)();

operator bool_type () const { return (someCondition ? &MyTestableClass::non_comparable_type : 0); }
};

class MyOtherTestableClass
{
private:
void non_comparable_type() {}
public:
typedef void (MyOtherTestableClass::* bool_type)();

operator bool_type () const { return (someCondition ? &MyOtherTestableClass::non_comparable_type : 0); }
};

For blocking the if (a == b) case, it depends on the fact that both types convert to incompatible pointer types.

C++ safe bool wrapper

You can achieve this by explicitly deleting all other constructors.

struct Bool final
{
template<class T>
Bool(T) = delete;

Bool(bool value);
};

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 static safe_bool::to_unspecified_bool() function.
  • 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 including smart_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.
  • 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 >. If Derived already inherits from Base, then use boost::spirit::classic::safe_bool< Derived, Base >.
      • Provide a bool operator_bool() const member function.

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.

Is there a safe bool idiom helper in boost?

bool_testable<> in Boost.Operators looks promising.

The reference mentions that:

bool_testable provides the antithesis of
operator bool, such that the expression if (!p) is valid, whilst also
making operator bool safer by preventing accidental conversions to
integer types. ... bool_testable<> prevents these accidental
conversions by declaring a private conversion operator to signed char,
and not defining the body.



Related Topics



Leave a reply



Submit