3

The compiler doesn't see the function std::to_string, despite the using directive. Why is that?

#include <string>
namespace MySpace
{
    using namespace std;

    struct X
    {
        int n;
    };

    string to_string(X x)
    {
        return to_string(x.n);//Error here
    }
}

All works fine if I move the stuff out of MySpace to the global namespace, or if I explicitly add using std::to_string; declaration into MySpace.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
olpchk
  • 101
  • 5
  • 1
    what is the error? Btw to me this is a perfect example of why `using namespace` isnt nice. Why do you insist on having two meanings for `to_string` in one scope? – 463035818_is_not_an_ai Aug 20 '18 at 17:56
  • 1
    `std::to_string(x.n);` – Marek R Aug 20 '18 at 17:59
  • Effectively a duplicate of [this question](https://stackoverflow.com/questions/48359856/unqualified-name-lookup-why-local-declaration-hides-declaration-from-using-dire). There `A` takes the place of `std` and `i` takes the place of `to_string`. – Troubadour Aug 20 '18 at 19:16
  • @user463035818 to make the compiler to choose suitable one – olpchk Aug 20 '18 at 19:50

4 Answers4

6

It's because of this [namespace.udir]:

During unqualified name lookup (6.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.

So using namespace std; for the purposes of unqualified name lookup in effect brings names into the global namespace, not into MySpace. Declarations in MySpace hide declarations from namespace std introduced in this manner.

If you move everything into the global namespace, it starts to work because your own to_string and std::to_string now appear in the same namespace, as far as unqualified lookup is concerned.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • In this case this is not true: "So using `namespace std;` in effect brings names into the global namespace":, proof: https://wandbox.org/permlink/D89pEfGouLYm57MC – Marek R Aug 20 '18 at 18:13
  • @MarekR you are not doing it correctly. Read the link from my answer, especially `...From the point of view of **unqualified name lookup of any name after a using-directive and until the end of the scope** in which it appears` – SergeyA Aug 20 '18 at 18:28
  • @MarekR this of course only applies to unqualified name lookup. Added clarification. – n. m. could be an AI Aug 20 '18 at 18:30
5

The reason is truly arcane, and has to do with the way both using directive and overload resolution works.

First, let's look at the using directive. When you inject namespace with it within another namespace, it works by actually injecting the namespace into

the nearest enclosing namespace which contains both the using-directive and namespace [being used]. (https://en.cppreference.com/w/cpp/language/namespace#Using-directives).

In your case, such namespace would be global namespace, is it would be the only one encompassing the std and My Space. The effect of it would be that names, defined in namespace std would behave as if they are defined in global namespace.

Let's look at overload resolution now. When the function is looked up by the name, the name is first searched in local namespace, and if not found, search continues in surrounding namespace, then one level up... - until the name(s) is(are) found, or we reach global namespace. Once at least one name is found, search stops there, and a qualified overload is chosen from the set of names using overload rules. In your case, this search immediately yields a single name - to_string - which is than rejected, as it does not accept int argument (it only accepts X).

On the other hand, when you do not use MySpace, names from std are put in the global namespace as well, but your own to_string exists in global namespace now. As a result, multiple to_string versions are found in global namespace, including yours, and the proper one to_string(int) is than selected based on the argument type.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
2

The problem with the code is because of wrong usage, you are not calling std::to_string inside of definition of MySpace::to_string. So, it works fine in the namespace MySpace too, just shadows to_string function which declered in std namespace.

The following code compiles fine:

namespace MySpace
{
    using namespace std;

    struct X
    {
        int n;
    };

    string to_string(X x)
    {
        return std::to_string(x.n); // No error anymore here
    }
}
eneski
  • 1,575
  • 17
  • 40
  • 1
    This doesn't answer why it works outside of namespace. – SergeyA Aug 20 '18 at 18:08
  • No, it was not @SergeyA. Because my approach was not correct. I edited my answer and I think that this answer is the correct one. Fully fully qualified namespace solves the problem – eneski Aug 20 '18 at 18:17
  • Nope, it still doesn't address the difference between using `MySpace` and not. – SergeyA Aug 20 '18 at 18:18
  • Yes, you are right. It is already specified that using `std::` solves the problem at end of the question. – eneski Aug 20 '18 at 18:23
-1

Best approach is to import specific functions into a name space.

#include <string>
#include <iostream>

namespace MySpace
{
    using std::to_string;

    struct X
    {
        int n;
    };

    std::string to_string(const X &x)
    {
        return to_string(x.n);
    }
}

https://wandbox.org/permlink/BD520ZCACv9hwF4q

Marek R
  • 32,568
  • 6
  • 55
  • 140