Linking error due to `<<` overload inside class nested within templated class

48 Views Asked by At

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.

0

There are 0 best solutions below