boost::format和自定义打印std容器

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 <<来打印与我的命名空间无关的类型。除了在boost/format/feed_args.hpp中添加using声明之外,是否有一种方便的方法让boost::format查找我的operator <<

1
我强烈建议您查看这个问题,因为它基本上回答了您的需求。尽管您实际的问题是关于operator<<的,但我不会投票将其关闭为重复问题。 - Xeo
2
@Xeo:我的实际代码使用非常类似的方法打印任何容器。不管怎样,问题不在于如何使用operator <<打印容器,而是如何使得同一重载对于Koenig无法满足要求的事情也能起作用。 - Travis Gockel
4个回答

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);

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(参数相关查找 - 常被归因于Andrew Koenig,但我认为他不应该承担全部责任)引起的。
即使在您的本地上下文中,在模板函数中使用您的operator<<也无法正常工作。
一个欺骗性的技巧是将您定义的operator<<放入namespace std中。这是被禁止的,但在您的情况下可能有效,但仅当它在其使用之前放置,并且可能是问题所在。
还可能有其他选项,例如定义自己的Set模板。我进行了实验。
    template<typename T> using Set=std::set<T>;

但是没有找到一个不需要

的解决方案。

    using np::operator<<;

yuyoyuppe 提供。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接