Here's the functionality I am expecting to achieve:
darray<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
std::cout << a << std::endl; // displays: {1, 2, 3}
My implementation:
template <typename T>
class darray
{
private:
long m_capacity;
long m_size;
T* m_data;
void resize();
public:
// constructors & destructors
darray();
// operations
void push_back(T);
std::ostream& print(std::ostream&) const;
template<typename U> friend std::ostream& operator<<(std::ostream& os, U const& ar);
};
template<typename T>
std::ostream& darray<T>::print(std::ostream& os) const
{
os << "{ ";
for (size_t i = 0; i < m_size; i )
{
os << m_data[i] << ", ";
if ( i == m_size - 1 )
os << m_data[i];
}
os << " }\n";
return arr;
}
template<typename U>
std::ostream& operator<<(std::ostream& os, U const& obj)
{
return obj.print(os);
}
produces an error:
error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘const char [66]’)
But, when I change the parameter of operator<< to accept a darray<U>
instead , it works fine:
template<typename U>
std::ostream& operator<<(std::ostream& os, darray<U> const& obj)
{
return obj.print(os);
}
What am I missing here?
Update:
I also tried doing this, changing the parameter to darray<U>
type in the definition and the implementation, but it still produces the same error:
template <typename T>
class darray
{
private:
long m_capacity;
long m_size;
T* m_data;
void resize();
public:
// constructors & destructors
darray();
// operations
void push_back(T);
std::ostream& print(std::ostream&) const;
template<typename U> friend std::ostream& operator<<(std::ostream& os, darray<U> const& ar);
};
template<typename T>
std::ostream& darray<T>::print(std::ostream& os) const
{
os << "{ ";
for (size_t i = 0; i < m_size; i )
{
os << m_data[i] << ", ";
if ( i == m_size - 1 )
os << m_data[i];
}
os << " }\n";
return os;
}
template<typename U>
std::ostream& operator<<(std::ostream& os, darray<U> const& obj)
{
return obj.print(os);
}
CodePudding user response:
Friend functions in template classes have to be defined inside the class declaration. This is the only way I have found to have the friend function to correctly accept an instance of the templated class with the expected template.
So here I would write:
...
friend std::ostream& operator<<(std::ostream& os, darray<T> const& ar) {
ar.print(os);
return os;
}
...
But beware: your class contains a raw pointer to allocated memory which is probably deleted in the class destructor. Per the rule of five, you must explicitely declare (or delete) the copy/move constructors and assignment operators.
CodePudding user response:
In your darray<T>::print
function, if you change
os << m_data[i] << ", ";
to
os << m_data[i];
os << ", ";
then the compiler doesn't complain and it works fine. I don't know why.