Вопрос по namespaces, boost-format, c++, boost – boost :: format и нестандартная печать стандартных контейнеров

10

У меня есть функция в моем пространстве именns это помогает мне печатать контейнеры STL. Например:

template <typename T>
std::ostream& operator<<(std::ostream& stream, const std::set<T>& set)
{
    stream << "{";
    bool first = true;
    for (const T& item : set)
    {
        if (!first)
            stream << ", ";
        else
            first = false;
        stream << item;
    }
    stream << "}";
    return stream;
}

Это прекрасно работает для печати сoperator << непосредственно:

std::set<std::string> x = { "1", "2", "3", "4" };
std::cout << x << std::endl;

Однако, используяboost::format невозможно:

std::set<std::string> x = { "1", "2", "3", "4" };
boost::format("%1%") % x;

Проблема довольно очевидна: Boost не имеет ни малейшего представления, что я хотел бы использовать егоoperator << печатать типы, которые не имеют ничего общего с моим пространством имен. Вне добавленияusing объявление вboost/format/feed_args.hppЕсть ли удобный способ сделатьboost::format искать мойoperator <<?

Я настоятельно рекомендую вам взглянуть наthis question, так как это в основном отвечает вашим потребностям. Я не буду голосовать, чтобы закрыть как дубликат, так как ваш реальный вопрос отличается (оoperator<<). Xeo
@Xeo: мой настоящий код использует очень похожий подход к печати любого контейнера. В любом случае, проблема не в том, как напечатать контейнер сoperator <<это то, как заставить ту же самую перегрузку работать на вещи, где Кениг не делает то, что я хочу. Travis Gockel

Ваш Ответ

4   ответа
4

что самый простой способ - предоставить тонкую оболочку в собственном пространстве имен для каждого из операторов, которые вы хотите переопределить. Для вашего случая это может быть:

namespace ns
{
    namespace wrappers
    {
        template<class T>
        struct out
        {
            const std::set<T> &set;

            out(const std::set<T> &set) : set(set) {}

            friend std::ostream& operator<<(std::ostream& stream, const out &o)
            {
                stream << "{";
                bool first = true;
                for (const T& item : o.set)
                {
                    if (!first)
                        stream << ", ";
                    else
                        first = false;
                    stream << item;
                }
                stream << "}";
                return stream;
            }
        };
    }

    template<class T>
    wrappers::out<T> out(const std::set<T> &set)
    {
        return wrappers::out<T>(set);
    }
}

Тогда используйте это так:

std::cout << boost::format("%1%") % ns::out(x);
Это очень похоже на решение, которое я на самом деле использовал. Я также опубликовал свое решение. Travis Gockel
1

namespace boost // or __gnu_cxx
{
    using np::operator<<;
}
#include <boost/format/feed_args.hpp>
0

как уже отмечалось, связана с ADL (поиск в зависимости от аргумента - часто приписывается Эндрю Кенигу, но я считаю, что он не должен брать всю вину).

Даже в вашем локальном контексте он не будет работать в шаблонной функции, где вы намереваетесь использоватьoperator<<.

Одна хитрость в том, чтобы поставитьoperator<< вы определяете вnamespace std, Это верботен, но он может работать в вашем случае, но только если он помещен перед его использованием, и это может быть проблемой.

Могут быть и другие варианты, такие как определение собственного шаблона Set. Я экспериментировал с

    template<typename T> using Set=std::set<T>;

но не смог получить решение, которое работало без

    using np::operator<<;

yuyoyuppe предоставляется.

5

с которым я на самом деле остановился, очень похоже на Answeror, но оно работает для всего:

namespace ns
{

template <typename T>
class FormatWrapper
{
public:
    explicit FormatWrapper(const T& x) :
            ref(x)
    { }

    friend std::ostream& operator<<(std::ostream& stream,
                                    const FormatWrapper<T>& self
                                   )
    {
        // The key is that operator<< is name lookup occurs inside of `ns`:
        return stream << self.ref;
    }
private:
    const T& ref;
};

template <typename T>
FormatWrapper<T> Formatable(const T& x)
{
    return FormatWrapper<T>(x);
}

}

Так что использование это:

boost::format("%1%") % Formatable(x);

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