0
#include <iostream>

namespace outside {
  struct A { 
    int outer = 42; 

    friend void print(A const& a, std::ostream& os) 
    { os << "outside::A " << a.outer << '\n'; }
  };
  namespace inside {
    struct A : outside::A { 
      int inner = 24; 
      void print(std::ostream& os) { } // Added for extra difficulty
      friend void print(A const& a, std::ostream& os) { 
        // outside::A::print(a, os); // <- does not compile
        os << " inside::A " << a.inner << '\n'; 
      }
    };
  } // inside
} // outside

int main(int argc, char *argv[]) {
  outside::A a_outside;
  outside::inside::A a_inside;

  print(a_outside, std::cout);
  print(a_inside, std::cout);
}

Is there a way to qualify the print function so that both base and derived members are printed? I could move both the friend functions to their closest enclosing namespaces:

#include <iostream>

namespace outside {
  struct A { int outer = 42; };
  void print(A const& a, std::ostream& os) 
  { os << "outside::A " << a.outer << '\n'; }

  namespace inside {
    struct A : outside::A { 
      void print(std::ostream& os) { } // Added for extra difficulty
      int inner = 24;
    };
    void print(A const& a, std::ostream& os) { 

      outside::print(a, os); // <- works
      os << " inside::A " << a.inner << '\n'; 
    }
  } // inside
} // outside

int main(int argc, char *argv[]) {
  outside::A a_outside;
  outside::inside::A a_inside;

  print(a_outside, std::cout);
  print(a_inside, std::cout);
}

This works, here's the result:

outside::A 42 outside::A 42 inside::A 24

Can the same be achieved with the friend functions though? Maybe using using?

EDIT: inside::A::print(std::ostream&) defeats the static cast suggest below, https://stackoverflow.com/a/22585103/710408. Any other options?

Community
  • 1
  • 1
dpj
  • 933
  • 1
  • 7
  • 14

2 Answers2

1

I find possible solution:

friend void print(A const& a, std::ostream& os) { 
    print(static_cast<const outside::A&>(a), os);
    os << " inside::A " << a.inner << '\n'; 
}

Some info why this dont work: https://stackoverflow.com/a/382077/1938348 Conclusion is simple when you define friend function in class body its invisible unless you use ADL. To made it work as you excepted you need change place of declaration:

namespace outside {
  struct A { 
    int outer = 42; 

    friend void print(A const& a, std::ostream& os);
  };
  void print(A const& a, std::ostream& os) {
    os << "outside::A " << a.outer << '\n';
  }
  namespace inside {
    struct A : outside::A { 
      int inner = 24; 

      friend void print(A const& a, std::ostream& os);
    };
    void print(A const& a, std::ostream& os) { 
      outside::print(a, os);
      os << " inside::A " << a.inner << '\n'; 
    }
  } // inside
} // outside
Community
  • 1
  • 1
Yankes
  • 1,958
  • 19
  • 20
  • This is good, thanks for the link too. I have, somewhat unfairly, added a member with the same name that defeats the static cast... Any thoughts? – dpj Mar 23 '14 at 00:13
  • then you need use second example. You cant use ADL and friend function be in class definition, because he find member function first (its defined in that same scope). ADL was designed to resolve clash from different namespaces not clash from the same class. Alternative change name of that member class. – Yankes Mar 23 '14 at 12:17
0

Do you mean:

  friend void print(A const& a, std::ostream& os) { 
    // outside::A::print(a, os);
    print(static_cast<const outside::A&>(a), os);
    os << " inside::A " << a.inner << '\n'; 
  }
grisha
  • 1,247
  • 1
  • 14
  • 20