Безопасная идиома bool в boost?

Предоставляет ли библиотека boost реализацию безопасной идиомы bool, чтобы я мог извлечь из нее свой класс?

Если да - где это?

Если нет - каковы мои альтернативы, кроме его реализации?


Я нашел следующий аналогичный вопрос: "Есть ли безопасный помощник идиомы bool в boost?", и принятый ответ предполагает использование bool_testable<> в Boost.Operators.

К сожалению, когда я проверил boost manual, я не смог его найти. Код, использующий его, также не скомпилирован.

Я также наткнулся на другой вопрос SO "Был ли boost:: bool_testable < > перемещен или удален?", и комментарий там говорит о том, что bool_testable на самом деле никогда сделанный для любой версии версии boost.

Существует также интересная статья > статьи Bjorn Karlsson по теме, которая содержит код, который можно было бы скопировать в мой проект. Однако я надеюсь, что есть общепринятая и поддерживаемая библиотека утилиты (например, boost), которая уже реализует это.


По причинам совместимости я не хочу полагаться на С++ 11.

Ответ 1

Я не знаю общепринятой библиотеки утилиты, которая обеспечивает идиому safe-bool. В Boost было несколько попыток, и они часто приводят к дебатам о том, как обеспечить реализацию safe-bool (соглашения об именах, макросы, встроенные вложения, наследование). В результате в Boost существует не менее трех реализаций, только с одной из реализаций, Boost.Spirit.Classic safe_bool, предназначенных для внешних использовать.


Подробности и концепции для каждой реализации:

  • Boost.Range safe_bool
    • Содержится в каталоге подробностей, поэтому он явно не предназначен для внешнего использования.
    • Реализовано с использованием вспомогательного типа шаблона и статических функций-членов.
    • Ожидается, что класс с поддержкой safe-bool:
      • Предоставить функцию члена operator boost::range_detail::safe_bool< MemberPtr >::unspecified_bool_type() const, которая делегирует статическую функцию safe_bool::to_unspecified_bool().
  • Boost.SmartPtr operator_bool:
    • Содержится в каталоге подробностей, поэтому он явно не предназначен для внешнего использования.
    • Заголовочный файл предназначен для включения непосредственно в определение класса. См. shared_ptr.hpp для примера.
    • Требуется включить boost/detail/workaround.hpp, прежде чем включать smart_ptr/detail/operator.hpp.
    • Ожидается, что окружающий класс с поддержкой safe-bool будет:
      • Укажите тип this_type.
      • Укажите тип T.
      • Предоставить переменную участника T* px.
  • Boost.Spirit.Classic safe_bool
    • Предназначен для внешнего использования.
    • Использует шаблон CRTP.
    • Предназначен для поддержки цепочки базового класса, позволяя использовать boost::spirit::class::safe_bool без указания множественного наследования в производном классе.
    • Ожидается, что класс с поддержкой safe-bool:
      • Публично вытекает из boost::spirit::classic::safe_bool< Derived >. Если Derived уже наследуется от Base, используйте boost::spirit::classic::safe_bool< Derived, Base >.
      • Предоставить функцию члена bool operator_bool() const.

В этом примере используется Boost 1.50. Каждый класс должен оценивать значение true в булевом контексте, если целое число, переданное конструктору, больше 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 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 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;
}

Результат:

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

Я не знаю никаких альтернатив. Когда я столкнулся с идиомами safe-bool, большинство реализаций были вариантами копирования и вставки реализации, представленными в статье Bjorn Karlsson.

Ответ 2

Начиная с Boost 1.55, в Boost.Core есть заголовок <boost/core/explicit_operator_bool.hpp>/licit_operator_bool.hpp>. От вас требуется определить bool operator!() И использовать BOOST_EXPLICIT_OPERATOR_BOOL() (есть также варианты этого BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() и BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()).

В документации есть пример:

template< typename T >
class my_ptr
{
    T* m_p;

public:
    BOOST_EXPLICIT_OPERATOR_BOOL()

    bool operator!() const
    {
        return !m_p;
    }
};