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查找 my operator <<

4

4 回答 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);
于 2012-10-03T13:57:53.940 回答
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);
于 2012-10-03T09:14:00.507 回答
1

你可以尝试这样的事情:

namespace boost // or __gnu_cxx
{
    using np::operator<<;
}
#include <boost/format/feed_args.hpp>
于 2012-08-18T23:35:21.387 回答
0

已经提到的问题是由于 ADL(依赖于参数的查找 - 通常归因于 Andrew Koenig,但我相信他不应该受到所有责备)。

即使在您的本地上下文中,它也无法在您打算使用operator<<.

一种作弊技巧是将operator<<您定义的内容放入namespace std. 那是禁止的,但它可能适用于你的情况,但前提是它被放在它的使用之前,这可能是问题所在。

可能还有其他选项,例如定义您自己的 Set 模板。我尝试过

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

但如果没有

    using np::operator<<;

yuyoyuppe 提供。

于 2012-08-23T15:37:29.777 回答