【问题标题】:boost::format and custom printing a std containersboost::format 和自定义打印标准容器
【发布时间】:2012-05-30 00:14:14
【问题描述】:

我的命名空间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 &lt;&lt; 打印:

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

【问题讨论】:

  • 我强烈建议您看看this question,因为它基本上可以满足您的需求。不过,由于您的实际问题不同(关于operator&lt;&lt;),我不会投票关闭作为重复项。
  • @Xeo:我的实际代码使用非常相似的方法来打印任何容器。无论如何,问题不在于如何使用operator &lt;&lt; 打印容器,而在于如何使同样的重载适用于 Koenig 不做我想做的事情。

标签: c++ boost namespaces boost-format


【解决方案1】:

我实际使用的解决方案与 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);

【讨论】:

    【解决方案2】:

    我认为最干净的方法是在您自己的命名空间中为您想要覆盖的每个运算符提供一个瘦包装器。对于您的情况,可以是:

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

    【讨论】:

    • 这和我实际使用的解决方案非常相似。我也发布了我的解决方案。
    【解决方案3】:

    你可以试试这样的:

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

    【讨论】:

      【解决方案4】:

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

      即使在您的本地环境中,它也无法在您打算使用 operator&lt;&lt; 的模板函数中工作。

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

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

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

      但如果没有

      ,则无法获得有效的解决方案
          using np::operator<<;
      

      yuyoyuppe 提供。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-17
        • 1970-01-01
        • 2012-03-12
        • 1970-01-01
        • 1970-01-01
        • 2010-12-11
        相关资源
        最近更新 更多