Как работает разрешение перегрузки операторов в пространствах имен?

Обнаружил странное поведение C++ разрешения перегрузки оператора -, объяснить не могу. Указатель на какой-то ресурс, описывающий его, был бы так же хорош, как и ответ.

У меня есть 2 единицы перевода. В одном (под названием util.cpp/h )я объявляю и определяю два оператора (я опускаю реальные реализации для удобства чтения, проблема возникает в любом случае):

// util.h
#ifndef GUARD_UTIL
#define GUARD_UTIL

#include <iostream>

std::istream& operator>>(std::istream& is, const char* str);
std::istream& operator>>(std::istream& is, char* str);
#endif

И:

//util.cpp
#include "util.h"
#include <iostream>

std::istream& operator>>(std::istream& is, const char* str) {
  return is;  
}
std::istream& operator>>(std::istream& is, char* str) {
  return is;  
}

Эти операторы, конечно, находятся в глобальном пространстве имен, поскольку они работают со стандартными типами и встроены -в типы и должны использоваться везде. Они просто отлично работают из глобального пространства имен (, например. из main ())или с явным указанием компилятору, что они находятся в глобальном пространстве имен (см. пример кода ).

В другой единице перевода (, называемой test.cpp/h ), я использую эти операторы в пространстве имен. Это работает, пока я не поставлю аналогичный оператор в это пространство имен. Как только этот оператор добавлен, компилятор (, например. gcc или clang )больше не могут найти жизнеспособный оператор>>.

// test.h
#ifndef GUARD_TEST
#define GUARD_TEST

#include <iostream>

namespace Namespace {
  class SomeClass {   
    public:
      void test(std::istream& is);
  };

  // without the following line everything compiles just fine
  std::istream& operator>>(std::istream& is, SomeClass& obj) { return is; }; 
}

#endif

И:

//test.cpp
#include "test.h"
#include "util.h"
#include <iostream>

void Namespace::SomeClass::test(std::istream& is) {
  ::operator>>(is, "c"); //works
  is >> "c" //fails
}

Почему компилятор находит правильный оператор, когда в пространстве имен нет operator>>, но не может найти, когда он есть? Почему оператор влияет на способность компилятора найти правильный, даже если он имеет другую сигнатуру?

Одной из попыток исправить это было поставить

std ::istream& operator>> (std ::istream& is, const char *str ){ ::operator>> (is, str ); }

в пространство имен, но тогда компоновщик жалуется на предыдущие определения. Так что дополнительно :Почему компоновщик может найти то, чего не находит компилятор?

10
задан hildensia 6 July 2012 в 09:49
поделиться