ostream operator << в пространстве имен скрывает другой ostream::operator

Используя gcc версии 5.2.0 (GCC) с --std= C++14, следующий код больше не компилируется, если закомментированный оператор ostream в пространстве имен MyNamespace не закомментирован. Это ошибка или особенность? (Компилировать с помощью g++ -c --std= C++14 x.cxx)

#include <string>
#include <iostream>

typedef std::pair<std::string, std::string> StringPair;

std::ostream& operator<<( std::ostream&, const StringPair &pair) {
  std::cout <<pair.first<<"."<<pair.second;
}

namespace MyNamespace {
  class MyClass {};
  //std::ostream& operator<< (std::ostream&, const MyClass &);
  void xxx ();
}

void MyNamespace::xxx () {
  StringPair pair;pair.first="1";pair.second="2";
  std::cout <<pair<<std::endl;
}

Сообщение об ошибке, которое я получаю с оператором << без комментариев:

x.cxx: In function ‘void MyNamespace::xxx()’:
x.cxx:18:13: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘StringPair {aka std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >}’)
std::cout <<pair<<std::endl;
         ^

1 ответ

Решение

Как указано здесь, это пример сокрытия имени. Определяя operator<< в пространстве имен MyNamespace все определения из более высоких пространств имен (например, глобальных) скрыты.

Обратите внимание, что, как указано здесь:

[...] эта функция не мешает поиску Кенига [...], поэтому операторы ввода-вывода из std:: все еще будет найден.

( подробности о поиске Кенига)

Решение состоит в том, чтобы ссылаться на перегрузку в другом пространстве имен с помощью using директива, как описано здесь и здесь. Об этом упоминалось в комментариях Михаила Настенко.

таким образом using ::operator<<;, с :: ссылаясь на глобальное пространство имен.

Таким образом код станет:

#include <string>
#include <iostream>

typedef std::pair<std::string, std::string> StringPair;

std::ostream& operator<<(std::ostream& os, const StringPair &pair) {
    os << pair.first << '.' << pair.second;
    return os;
}

namespace MyNamespace {
    class MyClass {};
    using ::operator<<;
    std::ostream& operator<< (std::ostream&, const MyClass &);
    void xxx();
}

void MyNamespace::xxx() {
    StringPair pair("1","2");
    std::cout<<pair<<std::endl;
}

int main() {
    MyNamespace::xxx();
    return 0;
}

пример на колиру

Другие вопросы по тегам