This C++ code compiles and runs perfectly, as I expect:
template <typename T> struct S { T *p; };
template <typename T>
bool operator == (S<T> &a, S<T> &b) { return a.p == b.p; }
int main () { int i; S<int> a = {&i}, b = {&i}; return a == b; }
However, if I try to do the same with the inner struct of an outer struct...
template <typename T> struct O { struct I {T *p;}; };
template <typename T>
bool operator == (O<T>::I &a, O<T>::I &b) { return a.p == b.p; }
int main () { int i; O<int>::I a = {&i}, b = {&i}; return a == b; }
... then it doesn't compile anymore (gcc version 8.3.0, Debian GNU/Linux 10):
1.cpp:4:25: error: declaration of ‘operator==’ as non-function
bool operator == (O<T>::I &a, O<T>::I &b) { return a.p == b.p; }
^
[...]
Why is it so? I also do not understand the above error message.
Note that I'm aware that I can make it work by defining the operator as a member function of the inner struct:
template <typename T>
struct O2 {
struct I2 {
T *p;
bool operator == (I2 &b) { return p == b.p; }
};
};
int main () { int i; O2<int>::I2 a = {&i}, b = {&i}; return a == b; }
However, if somehow possible, I'd rather use the non-member function version, because I find it more symmetric and therefore clearer.
Also, partly by trial and error, I found that the following symmetric version works...
template <typename T>
struct O3 {
struct I3 { T *p; };
friend bool operator == (I3 &a, I3 &b) { return a.p == b.p; }
};
int main () { int i; O3<int>::I3 a = {&i}, b = {&i}; return a == b; }
... but I do not really understand what is happening above. First, given that a friend declaration "grants a function or another class access to private and protected members of the class where the friend declaration appears", I do not understand how it helps in the code above, given that we're always dealing with structs and therefore with public members.
Second, if I remove the friend
specifier, then it doesn't compile anymore. Also, the [...] operator== [...] must have exactly one argument
error message makes me think that in this case the compiler expects me to define a member function operator==
whose left operand is O3
, not I3
. Apparently, however, the friend
specifier changes this situation; why is it so?
Read more here: https://stackoverflow.com/questions/65710351/operator-overloading-for-nested-struct-only-working-as-member-or-friend-function
Content Attribution
This content was originally published by Pablo M. S. Farias at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.