Вопрос по boost, boost-test, c++ – BOOST_CHECK_EQUAL с парой <int, int> и пользовательским оператором <<

7

При попытке сделать BOOST_CHECK_EQUAL (пара, пара), gcc не находит оператора потока для пары, несмотря на его объявление. Самое смешное, что std :: out находит оператора.

ostream& operator<<(ostream& s, const pair<int,int>& p) {
    s << '<' << p.first << ',' << p.second << '>';
    return s;
}


BOOST_AUTO_TEST_CASE(works)
{
    pair<int,int> expected(5, 5);
    pair<int,int> actual  (5, 5);
    std::cout << expected << std::endl;
    std::cout << actual   << std::endl;
    BOOST_CHECK(actual == expected);
}

BOOST_AUTO_TEST_CASE(no_work)
{
    pair<int,int> expected(5, 5);
    pair<int,int> actual  (5, 5);
    BOOST_CHECK_EQUAL(actual, expected);
}

Это не компилируется с ошибкой:

...  instantiated from here
../boost-atp/release/include/boost/test/test_tools.hpp:326:9: error: no match for ‘operator<<’ in ‘ostr << t’
@Raffi Этот вопрос выглядит как дубликат этого вопроса, имеет меньше деталей. Может быть, имеет смысл пометить его как дубликат и переместить свой ответ сюда, чтобы мы не заставляли пользователей прыгать? Я тоже могу это принять. Спасибо! nishantjr
new способ определения собственной печати для пользовательских типов объясняется здесь:stackoverflow.com/a/44810846/1617295 , а такжеthis is the official documentation этой функции. Raffi

Ваш Ответ

3   ответа
10

operator<< вstd лайкОтвет Ремуса является неопределенным поведением в черновике C ++ 14 (раздел N4296: 17.6.4.2.1). Boost обеспечивает крючок (используется этим ответом) и вы можете написать:

namespace boost
{
    namespace test_tools
    {
        template<typename T,typename U>
        struct print_log_value<std::pair<T, U> >
        {
            void operator()(std::ostream& os, std::pair<T, U> const& pr)
            {
                os << "<" << std::get<0>(pr) << "," << std::get<1>(pr) << ">";
            }
        };
    }
}

print_log_value это шаблон, так что если вы не объявляете шаблонное значение, какpair<T,U>, вам нужно будет написать что-то вроде:

template<>
struct print_log_value<MyType>{ /* implementation here*/ };

Edit

Если вы используете boost 1.59 или новее, вам нужно использовать пространство именboost::test_tools::tt_detail вместо. То есть код должен запускаться:

namespace boost
{
    namespace test_tools
    {
        namespace tt_detail
        {
Ах! Это здорово! Это намного чище. nishantjr
0

способ настроить выходную строку для печати целых чисел в шестнадцатеричном виде. Инъекция оператора в пространство имен std будет работать, но каждый BOOST_CHECK в моем тесте будет напечатан в шестнадцатеричном виде.

Поэтому я ввел несколько пользовательских операторов в пространство имен boost, которые я мог бы контролировать с помощью некоторых глобальных операторов bool.

Смотрите мой ответ здесьповышение-чек-терпит неудачу к компиляции оператора-для-пользовательских-типов.

9

сам оператор в пространстве имен std:

namespace std
{
  ostream& operator<<(ostream& s, const pair<int,int>& p) {
    s << '<' << p.first << ',' << p.second << '>';
    return s;
  }
}

Обновление: возможно, поэтомуADL не работает (хотя бы на llvm):

Just like before, unqualified lookup didn't find any declarations with the name operator<<. Unlike before, the argument types both contain class types: one of them is an instance of the class template type std::basic_ostream, and the other is the type ns::Data that we declared above. Therefore, ADL will look in the namespaces std and ns for an operator<<. Since one of the argument types was still dependent during the template definition, ADL isn't done until the template is instantiated during Use, which means that the operator<< we want it to find has already been declared. Unfortunately, it was declared in the global namespace, not in either of the namespaces that ADL will look in!

Good news: Данный пример отсутствует в проекте стандарта C ++ 14 (раздел N4296: 17.6.4.2.1).Bad news: формулировка стандарта похожа на ту, которую вы цитировали. Единственными вещами, перечисленными как разрешенные в стандарте, являются шаблонные специализации.ostream& operator<<(ostream&, pair<int,int>) это не специализация шаблона, это перегрузка функции.
@njr: я изучал это некоторое время назад, но не нашел основную причину. Afaik GCC делает ADL, и поэтому делает llvm.
Формулировка такова: поведение программы на C ++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен в пространстве имен std, если не указано иное. Программа может добавить специализацию шаблона для любого стандартного шаблона библиотеки в пространство имен std, только если объявление зависит от типа, определенного пользователем, и специализация соответствует требованиям стандартной библиотеки для исходного шаблона и явно не запрещена.
Я не понимаю, почему ADL не применяется в BOOST_CHECK_EQUAL. Boost делает что-нибудь, чтобы остановить это? nishantjr
Это работает для меня, но это, кажется, неопределенное поведение (en.cppreference.com/w/cpp/language/extending_std ). Глядя, я обнаружил следующий ответ, который дает способ избежать неопределенного поведенияstackoverflow.com/a/17573165/309334

Похожие вопросы