Question

Why do I get a linker error for the following?

template<typename T, typename U>
class A {
public:
    class B;
};

template<typename T, typename U>
class A<T, U>::B {
    friend bool operator==(const B& b1, const B& b2);
};

template<typename T, typename U>
bool operator==(const typename A<T, U>::B& b1, const typename A<T, U>::B& b2) {
    return true;
}

int main() {
    A<char, int>::B b1;
    A<char, int>::B b2;

    if (b1 == b2) {
        return 0;
    } else {
        return 1;
    }
}

The error I get is:

Undefined symbols for architecture x86_64:
  "operator==(A<char, int>::B const&, A<char, int>::B const&)", referenced from:
      _main in test-qSCyyF.o
Was it helpful?

Solution

Because you're calling it and it has no definition!

This

template<typename T, typename U>
class A<T, U>::B {
    friend bool operator==(const B& b1, const B& b2);
};

is a declaration of a non-template friend function of A<T,U>::B class.

It matches the call (b1 == b2) just as well as the template operator you define further down but it is preferred because it is a non-template.

GCC even gives a warning with -Wnon-template-friend

warning: friend declaration 'bool operator==(const A::B&, const A::B&)' declares a non-template function [-Wnon-template-friend]
note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)

To fix, it provide the definition

template<typename T, typename U>
class A<T, U>::B {
    friend bool operator==(const B& b1, const B& b2) {
        return true;
    }
};

and get rid of the templated operator OR keep only the template one.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top