Search code examples
c++boostnamespacesboost-format

boost::format and custom printing a std containers


I have a function in my namespace ns that helps me print STL containers. For example:

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

This works great for printing with operator << directly:

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

However, using boost::format is impossible:

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

The problem is fairly obvious: Boost has no idea that I would like it to use my custom operator << to print types which have nothing to do with my namespace. Outside of adding a using declaration into boost/format/feed_args.hpp, is there a convenient way to make boost::format look for my operator <<?


Solution

  • I think the most clean way is to provide a thin wrapper in your own namespace for each of the operators you want to override. For your case, it can be:

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

    Then use it like this:

    std::cout << boost::format("%1%") % ns::out(x);