Search code examples
c++templatesostream

Output stream for generic container


I have created this template function:

// Output stream for container of type C
template<class C>
ostream& operator<<(ostream& os, const C& c) {
    os << "[";
    for (auto& i : c) {
        os << i;
        if (&i != &c.back()) os << ", ";
    }
    os << "]" << endl;
    return os;
}

but I have this error:

error: use of overloaded operator '<<' is ambiguous (with operand types 'std::ostream' (aka 'basic_ostream') and 'const char [2]')

The error is in the first line of the body of the function.


Solution

  • This declaration

    template<class C>
    ostream& operator<<(ostream& os, const C& c)
    

    is a match for any type. In particular, when you call inside that operator

    os << "[";
    os << i;
    os << "]" << endl;
    

    For all this calls your operator is a match in addition to the already existing output operators for strings and endl.

    Don't provide operators for types you don't own. Instead you can write a

    void print(const my_container&);
    

    or use a tag to resolve ambiguity. For example you could use a

    template <typename T>
    struct pretty_printed_container {
        const T& container;
    };
    
    template <typename T>
    pretty_printed_container<T> pretty_print(const T& t) { return {t};}
    

    modify your output operator accordingly

    template<class T>
    std::ostream& operator<<(std::ostream& os, const pretty_printed_container<T>& c) {
        os << "[";
        for (const auto& i : c.container) {
            os << i;
            if (&i != &c.container.back()) os << ", ";
        }
        os << "]" << std::endl;
        return os;
    }
    

    And then use it like this

    int main() {
        std::vector<int> x{1,2,3,4,5};
        std::cout << pretty_print(x);
    }
    

    Output:

    [1, 2, 3, 4, 5]