Cxx-prettyprint (для стандартных контейнеров) определяет свои операторы вывода внутри пространства имен std - это стандартное нарушение?

Я успешно использую cxx-prettyprint: C ++ Container Pretty-Printer < / em> для записи значений контейнера. (См. Также Контейнеры STL C ++ с красивой печатью). Он прекрасно работает даже на старый компилятор VS-2005 (VC8) (с заголовком prettyprint98.hpp) также хорошо работает на VS2017-2019 при его использовании, например чтобы значения контейнера можно было распечатать в модульных тестах.

Изучая его совместимость с Boost.Format, я с удивлением обнаружил, что он просто работает из коробки, когда другие вопросы говорят о том, что этого не должно быть, потому что ADL не должен работать с оператором вывода, предоставленным пользователем.

Заглянув в заголовок cxx-pp, я обнаружил, что это просто работает, потому что библиотека определяет свои операторы вывода внутри пространства имен std:

// Main magic entry point: An overload snuck into namespace std.
// Can we do better?

namespace std
{
    // Prints a container to the stream using default delimiters

    template<typename T, typename TChar, typename TCharTraits>
    inline typename enable_if< ::pretty_print::is_container<T>::value,
                              basic_ostream<TChar, TCharTraits> &>::type
    operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
    {
        return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
    }
}    
....

Очевидно, авторы не были уверены в этом на 100%: qq "Можем ли мы сделать лучше?"

Добавление чего-либо в пространство имен std - это формально UB:

[C++11: 17.6.4.2.1/1]: Поведение программы C ++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен в пространстве имен std, если не указано иное. Программа может добавить специализацию шаблона для любого шаблона стандартной библиотеки в пространство имен std только в том случае, если объявление зависит от определяемого пользователем типа, а специализация соответствует требованиям стандартной библиотеки для исходного шаблона и не запрещена явно.

Итак, это в cxx-pp формально UB, или это специализация шаблона (мне это не кажется).

Комментарии относительно практического воздействия этого, если только UB, будут очень приветствоваться.


person Martin Ba    schedule 04.08.2014    source источник
comment
Да, задним числом вставлять что-то в std, вероятно, было не самой хорошей идеей. (Просто это так здорово сработало ...) Приветствуются исправления и запросы на вытягивание. (И да, подтолкните меня, если я не отвечу вовремя.)   -  person Kerrek SB    schedule 04.08.2014
comment
@KerrekSB - На самом деле я не уверен, что это такая плохая идея. Если бы вы этого не сделали, разве все контейнеры не должны быть обернуты в тип оболочки, включающий ADL, как я связал или как уже упоминалось здесь   -  person Martin Ba    schedule 04.08.2014
comment
Немного обновил библиотеку C ++ 11. Кортежи и пары теперь являются контейнерами, поэтому стало намного меньше изворотливых перегрузок. Я не знаю, смогу ли я избавиться от основной перегрузки в пространстве имен std, поскольку у нас могут быть аргументы, которые только в std, например std::cout и std::vector<int>.   -  person Kerrek SB    schedule 12.08.2014
comment
@KerrekSB - вы можете избавиться от него, только если пользователи соглашаются делать cout << pretty_print(arg) << ... ... что, IMHO, вариант, и не такой уж плохой. Конечно, это часто выходит из строя в общем случае, и для меня перегрузка std, хотя и не соответствует требованиям, является лучшим вариантом, чем если бы она не работала в некоторых случаях.   -  person Martin Ba    schedule 12.08.2014


Ответы (1)


Это покрывается [namespace.std] / 1 в стандарте (который цитируется в вопросе, но воспроизводит его здесь, поскольку он также является ответом):

Поведение программы C ++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен в пространстве имен std, если не указано иное.

Нет никаких «иных указаний» для перегрузок operator<< для новых определяемых пользователем типов.

Таким образом, поведение просто не определено (без диагностики).

На практике кажется, что код либо будет работать, либо нет, но, как и со всеми UB, мы должны быть осторожны, чтобы не исключить что-либо еще.

person M.M    schedule 16.06.2020