Boost:: формат и пользовательская печать контейнеров std
У меня есть функция в моем пространстве имен 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 <<
?
Ответы
Ответ 1
Я думаю, что самый чистый способ - предоставить тонкую оболочку в вашем собственном пространстве имен для каждого из операторов, которые вы хотите переопределить. Для вашего случая это может быть:
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);
Ответ 2
Решение, с которым я действительно перешел, очень похоже на "Ответчик", но оно работает на все:
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);
Ответ 3
Вы можете попробовать что-то вроде этого:
namespace boost // or __gnu_cxx
{
using np::operator<<;
}
#include <boost/format/feed_args.hpp>
Ответ 4
Проблема, как уже отмечалось, связана с ADL (зависимость от зависимостей от аргументов - часто приписывается Эндрю Кенигу, но я считаю, что он не должен все винить).
Даже в вашем локальном контексте он не будет работать в функции шаблона, где вы намерены использовать operator<<
.
Один трюк заключается в том, чтобы поместить operator<<
в namespace std
. Это verboten, но это может работать в вашем случае, но только если оно помещено перед его использованием, и это может быть проблемой.
Могут быть дополнительные параметры, такие как определение собственного шаблона Set. Я экспериментировал с
template<typename T> using Set=std::set<T>;
но не смог получить решение, которое работало без
using np::operator<<;
предоставляется yuyoyuppe.