Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
207 views
in Technique[技术] by (71.8m points)

c++ - How does the operator overload resolution work within namespaces?

I found a strange behaviour of C++ resolution of operator-overloading, I can't explain myself. A pointer to some resource describing it would be just as nice as an answer.

I have 2 translation units. In one (called util.cpp/h) I declare and define two operators (I omit the real implementations for readabilty, the problam occurs anyway):

// 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

And:

//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;  
}

These operators are, if course in global namespace, since they operate on std types and built-in types and should be usable from everywhere. They just work fine from global namespace (e.g. from main()) or with explicitly telling the compiler that they are in global namespace (see code example).

In another translation unit (called test.cpp/h) I use these operators within a namespace. This works until I put a similar operator into this namespace. As soon as this operator is added, the compiler (e.g. gcc or clang) is not able to find a viable operator>> anymore.

// 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

And:

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

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

Why does the compiler find the correct operator when there is no operator>> in Namespace but fails to find when there is one? Why does the operator affect the ability of the compiler to find the correct one even if it has a different signature?

One attempt to fix this was to put

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

into Namespace, but than the linker complains about previous definitions. So additional: Why can the linker find something the compiler doesn't find?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is a name hiding issue. The standard says (c++03, 3.3.7/1)

A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).

The "name" on your case would be operator>> and namespaces constitute nested declarative regions.

The easiest way to fix that would be to use a using declaration where you declare the namespace-local operator<<:

namespace your_namespece {
    std::istream& operator>>(std::istream& is, SomeClass& obj) { return is; }; 
    using ::operator>>;
}

Note that this feature doesn't interfere with Koenig lookup (at least in your case, in principle, it can), so IO operators from std:: will still be found.

PS: Another possibility for working aroud this issue would be defining the operator for SomeClass as an inline friend. Such functions are declared at the namespace level (outside of "their" class), but are not visible from there. They can only be found by Koenig lookup.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...