0

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.

5
  • 3
    You friend a non-template function, yet your actual operator<< is a template. I'd move the definition of operator<< to the class body. Or you can friend the whole template. (Or declare the template beforehand and friend a specific specialization of it.) Commented Nov 10, 2023 at 5:29
  • @HolyBlackCat thanks a lot. When you say "friend the whole template", do you mean declaring operator<< as a templated friend function within gml::tensor<T>::shape? I've also tried specializing it, but to no avail. I appreciate the help. Commented Nov 10, 2023 at 5:55
  • 1
    Do you see any compiler warnings? Enable -Wall -Wextra at least. Commented Nov 10, 2023 at 6:04
  • 2
    "friend the whole template" - that would be template <Numeric T> friend std::ostream &operator<<(std::ostream&, const typename tensor<T>::shape&); inside of the class, I think. Commented Nov 10, 2023 at 6:36
  • @HolyBlackCat thanks a lot, I had tried that previously, but it didn't work either. I'll just define the function within the class :( I much appreciate the help! Commented Nov 10, 2023 at 15:37

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.