boost::format and custom printing a std containers

前端 未结 4 1980
感情败类
感情败类 2020-12-30 09:51

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

template 
std::ostream& operator<         


        
相关标签:
4条回答
  • 2020-12-30 10:12

    The solution I actually went with is quite similar to Answeror's, but it works for anything:

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

    So usage is:

    boost::format("%1%") % Formatable(x);
    
    0 讨论(0)
  • 2020-12-30 10:16

    The problem as already noted is because of ADL (argument dependent lookup - often attributed to Andrew Koenig, but I believe he shouldn't get all the blame).

    Even in your local context it wouldn't work in a template function where you intend to use your operator<<.

    One cheating trick is to put the operator<< you define into namespace std. That is verboten, but it might work in your case, but only if it is put before its usage and that might be the problem.

    There might be further options, such as defining your own Set template. I experimented with

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

    but couldn't get a solution that worked without the

        using np::operator<<;
    

    yuyoyuppe provided.

    0 讨论(0)
  • 2020-12-30 10:22

    You can try something like this:

    namespace boost // or __gnu_cxx
    {
        using np::operator<<;
    }
    #include <boost/format/feed_args.hpp>
    
    0 讨论(0)
  • 2020-12-30 10:29

    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);
    
    0 讨论(0)
提交回复
热议问题