I am trying to overload the stream insertion operator << to allow instances of my gml::tensor<T>::shape class to be printed to stdout.
I have reduced my code as much as possible in order to reproduce the source of the problem:
#include <iostream>
#include <concepts>
namespace gml {
template <typename T>
concept Numeric = requires (T value) {
T{1};
};
template <Numeric T>
class tensor;
template <Numeric T>
std::ostream &operator<<(std::ostream&, const typename tensor<T>::shape&);
template <Numeric T>
class tensor {
public:
class shape {
public:
shape() = default;
friend std::ostream &operator<<(std::ostream&, const shape&);
};
tensor() {
std::cout << "tensor ctor" << std::endl;
}
};
template <Numeric T>
std::ostream &operator<<(std::ostream &out, const typename tensor<T>::shape &s) {
return out << "PRINTING AT LAST!!!\n" << std::endl;
}
}
int main() {
gml::tensor<long double>::shape s;
std::cout << s << std::endl;
return 0;
}
The linker error I get is:
Undefined symbols for architecture arm64:
"gml::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, gml::tensor<long double>::shape const&)", referenced from:
_main in test-eaec7e.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I am beginning to think that what I wish to do is not possible.
I could define the << overload as a member function, but, before that, I'd like to know whether anything could be done to allow the function to be defined outside of gml::tensor<T>::shape.
Note: removing the tensor and operator<< forward declarations does not make any difference.
frienda non-template function, yet your actualoperator<<is a template. I'd move the definition ofoperator<<to the class body. Or you canfriendthe whole template. (Or declare the template beforehand andfrienda specific specialization of it.)friendthe whole template", do you mean declaringoperator<<as a templated friend function withingml::tensor<T>::shape? I've also tried specializing it, but to no avail. I appreciate the help.template <Numeric T> friend std::ostream &operator<<(std::ostream&, const typename tensor<T>::shape&);inside of the class, I think.