Отключить BOOST_CHECK для nullptr - PullRequest
0 голосов
/ 06 февраля 2019

С Boost Test ранее, чем версия 1.64, вы не можете сделать это:

SomeType* a_pointer = getPointer();
BOOST_CHECK_EQUAL(a_pointer, nullptr);

Это потому, что nullptr_t имеет неоднозначные перегрузки: Проблема повышения # 12778 и связанный с этим вопрос .Как и в ответах на вопрос, это может быть легко решено:

BOOST_CHECK(!a_pointer); // rely on boolean casting, or...
// cast nullptr away from nullptr_t
BOOST_CHECK_EQUAL(a_pointer, static_cast<SomeType*>(nullptr));

Однако, если вы поддерживаете несколько буст-версий, BOOST_CHECK_EQUAL(a_pointer, nullptr) легко проскользнуть на более новую платформу и сломать старуюиз них.

Одним из решений здесь является принудительное применение платформы CI с более старыми версиями Boost (что также полезно по другим причинам, особенно когда поддерживаемые версии Boost были расширены до 1.59, когда Boost Test 3 сильно изменился!).

Однако, полагаясь только на CI, чтобы поймать это, это большая задержка в цикле OODA (по сравнению с ошибкой локального компилятора) и требует доступа к сети и простого, но раздражающего танца VCS для исправления тривиальных изменений ви повторно отправьте задание.

Есть ли способ заставить его не скомпилироваться, даже если в противном случае Boost-версия его поддержит?

1 Ответ

0 голосов
/ 06 февраля 2019

В Boost Test это реализовано в commit 229e71199 для v1.64 с использованием точки настройки print_log_value :

template<>
struct BOOST_TEST_DECL print_log_value<std::nullptr_t> {
    void operator()( std::ostream& ostr, std::nullptr_t t ) {
        ostr << "nullptr";
    }
};

Это невозможно "отменить" функцию, определенную в другом модуле перевода (за исключением некоторых довольно неприятных хаков препроцессора).Так что на самом деле невозможно «повредить» функцию и вызвать сбой компиляции, если вы попытаетесь использовать эту функцию.

Однако у нас есть два лучших варианта: использовать метод Boost test, чтобы избежать печати этого типа, или выполнитьэто сами.


Избегайте печати nullptr_t

Вы используете существующую точку настройки Boost для предотвращения регистрации типа: BOOST_TEST_DONT_PRINT_LOG_VALUE:

// in your common test header
BOOST_TEST_DONT_PRINT_LOG_VALUE( std::nullptr_t )

Что это делаетТак как в Boost 1.59 определена функция print_log_value, которая ничего не делает:

#define BOOST_TEST_DONT_PRINT_LOG_VALUE( the_type )         \
namespace boost{ namespace test_tools{ namespace tt_detail{ \
template<>                                                  \
struct print_log_value<the_type > {                         \
    void    operator()( std::ostream&, the_type const& ) {} \
};                                                          \
}}}                                                         \                                                     

До 1,59 ( commit bae8de14b ), она определяется по-другому (не в tt_detail для начала), но идея та же.Это означает, что он будет работать по крайней мере до 1,58 и более ранних версий с использованием этого макроса.

Однако, поскольку в 1.64 была определена функция print_log_value, если вы просто добавите вышеупомянутый макрос, вы получите переопределениеошибки начиная с 1.64: та, которая ничего не делает из макроса DONT_PRINT, и та, которая печатает "nullptr".Таким образом, вы можете защитить его соответствующей версией Boost:

#if BOOST_VERSION < 106400
    BOOST_TEST_DONT_PRINT_LOG_VALUE( std::nullptr_t )
#endif

Теперь он не печатает nullptr при Boost <1.64 и печатает при 1.64 +: </p>

[ != 0xdeadbeef]        // < 1.64, using BOOST_TEST_DONT_PRINT_LOG_VALUE
[nullptr != 0xdeadbeef] // 1.64 +, using built-in implementation

Это можетбудьте достаточно хороши, если вы действительно не заботитесь о красоте регистрации в старых версиях Boost.


Сделайте это сами

Вы также можете реализовать собственную print_log_value пункт настройки.Тем не менее, обратите внимание, что пространство имен отличается до 1.59, и мы должны делать это только для <1.64, так как, опять же, мы переопределим функцию: </p>

// You don't need this bit if you don't support Boost Test <1.59.
#if BOOST_VERSION >= 105900
#    define BOOST_TEST_PRINT_NAMESPACE_OPEN namespace boost { namespace test_tools { namespace tt_details {
#    define BOOST_TEST_PRINT_NAMESPACE_CLOSE }}}
#else
#    define BOOST_TEST_PRINT_NAMESPACE_OPEN namespace boost { namespace test_tools {
#    define BOOST_TEST_PRINT_NAMESPACE_CLOSE }}
#endif

#if BOOST_VERSION < 106400

BOOST_TEST_PRINT_NAMESPACE_OPEN

template<>
struct print_log_value<nullptr_t> {
    inline void operator()(std::ostream& os, nullptr_t const& p) {
        os << "nullptr";
    }
};

BOOST_TEST_PRINT_NAMESPACE_CLOSE

#endif // End <1.64 condition

Теперь она напечатает то же самое:

[nullptr != 0xdeadbeef] // < 1.64, using DIY implementation
[nullptr != 0xdeadbeef] // 1.64 +, using built-in implementation
...