пространство имен, конфликт ADL члена класса

#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);
}

Есть ли способ квалифицировать функцию печати, чтобы печатались как базовые, так и производные члены? Я мог бы переместить обе дружественные функции в их ближайшие окружающие пространства имен:

#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);
}

Это работает, вот результат:

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

Однако можно ли добиться того же с помощью функций друзей? Может быть, используя using?

РЕДАКТИРОВАТЬ: inside::A::print(std::ostream&) побеждает статическое приведение, предлагаемое ниже, https://stackoverflow.com/a/22585103/710408. Любые другие варианты?


person dpj    schedule 22.03.2014    source источник


Ответы (2)


Я нахожу возможное решение:

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

Некоторая информация, почему это не работает: https://stackoverflow.com/a/382077/1938348 Вывод прост, когда вы определяете friend в теле класса она невидима, если вы не используете ADL. Чтобы заставить его работать так, как вы, вам нужно изменить место объявления:

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
person Yankes    schedule 22.03.2014
comment
Это хорошо, спасибо и за ссылку. Я несколько несправедливо добавил участника с таким же именем, который побеждает статический состав... Есть мысли? - person dpj; 23.03.2014
comment
тогда вам нужно использовать второй пример. Вы не можете использовать ADL и функцию друга в определении класса, потому что он сначала находит функцию-член (она определена в той же области). ADL был разработан для разрешения конфликтов из разных пространств имен, а не конфликтов из одного и того же класса. Альтернативное имя изменения этого класса-члена. - person Yankes; 23.03.2014

Ты имеешь ввиду:

  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'; 
  }
person grisha    schedule 22.03.2014