Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write an insertion operator function template?

I'm trying to write a single function template instead of a bunch of similar overloads for the insertion operator. The redundant overloaded versions work, but when I try to unite them in a single function template, the compiler complains of ambiguity. For example:


#include <iostream>
#include <list>

class fooBar
{
public:
    fooBar(int iVal): iValue(iVal) {}
    int getValue() {return iValue;}
    
private:
    int iValue;

};

class foo
{
public:
    foo()
    {
        for(int i = 0; i < 64; i++)
            lstFooBars.push_back(fooBar(i));
    }
    std::list<fooBar>& getList()
    {
        return lstFooBars;
    }

private:
    std::list<fooBar> lstFooBars;
    
};

class bar
{
public:
    bar()
    {
        for(int i = 0; i < 64; i++)
            lstFooBars.push_back(fooBar(i));
    }
    std::list<fooBar>& getList()
    {
        return lstFooBars;
    }

private:
    std::list<fooBar> lstFooBars;
    
};

std::ostream& operator<<(std::ostream& osOut, fooBar& fbrFooBar)
{
    osOut << fbrFooBar.getValue();

    return osOut;
}

template <typename T> std::ostream& operator<<(std::ostream& osOut, T& tContainer)
{
    for(fooBar fbrFooBar: tContainer.getList())
        osOut << "[" << fbrFooBar << "] ";

    return osOut;
}

int main()
{
    foo fooFoo;
    bar barBar;

    std::cout << std::endl << fooFoo << std::endl << std::endl;
    std::cout << std::endl << barBar << std::endl << std::endl;

    return 0;
}

...and the compiler tells me that:

test.cpp: In function ‘std::ostream& operator<<(std::ostream&, T&)’:
test.cpp:63:9: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘const char [2]’)
   63 |   osOut << "[" << fbrFooBar << "] ";
      |   ~~~~~ ^~ ~~~
      |   |        |
      |   |        const char [2]
      |   std::ostream {aka std::basic_ostream<char>}

Why does it work when you overload the same function over and over for each case and it doesn't compile like this? What am I missing here?

like image 872
Capitan Trueno Avatar asked Aug 06 '26 06:08

Capitan Trueno


1 Answers

You've inadvertedly added a possible overload for const char* by making this:

template<typename T>
std::ostream& operator<<(std::ostream& osOut, T& tContainer)

If you narrow it down a bit with SFINAE, it should work.

This overload will only work for types with a getList() member function for example:

template<typename T, typename U = decltype(std::declval<T>().getList())>
std::ostream& operator<<(std::ostream& osOut, T& tContainer)
like image 172
Ted Lyngmo Avatar answered Aug 07 '26 21:08

Ted Lyngmo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!