using directive and function overloading in a namespace [duplicate] - c++

This question already has an answer here:
Unqualified name lookup: Why local declaration hides declaration from using directive
(1 answer)
Closed 4 years ago.
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.

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.

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.

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

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

Related

variables declaration in anonymous namespace and definition in other place

Can someone explain why I can't define variable that was declared in anonymous namespace as global variable in another place?
#include <iostream>
namespace {
extern int number;
}
int number = 123;
void g() {
std::cout << number;
}
Compiler says that "Reference to 'number' is ambiguous" but I can't understand why it recognises declaration and definition as different things? Thank you in advance.
In general, the name being declared by a declaration is not looked up—after all, you can’t rely on finding a previous declaration when a name is first introduced. Of course, there is a similar process that traps things like
int x;
float x;
However, since it isn’t lookup it is not affected by using at all (including for an unnamed namespace). Another way of describing this distinction is that a declaration puts entities into namespaces and thus need not consider any other namespace in order to decide where to put an entity.
There are also cases where lookup does occur for (what might be) a declarator-id:
namespace N {using X=int;}
// using namespace N;
struct A {
A(X()); // ?
};
A has a member function with no parameters returning an A named X (with meaningless parentheses around its declarator); however, with the using-directive it instead has a constructor that takes a pointer to a function of no parameters returning an int. Similarly, in a declaration beginning
template<>
struct X<…
X must be fully looked up, even though a declaration of an explicit specialization must inhabit the same scope as the primary template (with leeway for inline namespaces), because it might continue
template<>
struct X<int>::Y<char> {…};
and not be a specialization of X at all.
For the unqualified name-lookup the compiler considers also nested unnamed namespaces in the global namespace,
You declared two different objects with the same name in the global namespace and in the nested unnamed namespace.
The using directive for unnamed namespace is implicitly inserted in the enclosing namespace.
Consider the following demonstration program
#include <iostream>
namespace N
{
extern int number;
}
using namespace N;
int number = 123;
int main()
{
std::cout << number << '\n';
}
The compiler will issue an error due to the ambiguity for the unqualified reference to the name number in this statement
std::cout << number << '\n';
The similar situation takes place with an unnamed namespace because the using directive is implicitly inserted in the enclosing namespace.
From the C++ 20 Standard (9.8.2 Namespace definition)
7 Members of an inline namespace can be used in most respects as
though they were members of the enclosing namespace. Specifically, the
inline namespace and its enclosing namespace are both added to the set
of associated namespaces used in argument-dependent lookup (6.5.3)
whenever one of them is, and a using directive (9.8.4) that names
the inline namespace is implicitly inserted into the enclosing
namespace as for an unnamed namespace (9.8.2.2).

Why am I able to use the names in the std namespace even though I'm "using namespace std;"?

Isn't there already a max function in the algorithm header file?
And by using namespace std;, I'm importing the function to the global namespace (which takes to arguments, and in this case both would be integers, so it shouldn't be an overload).
So why isn't there any naming conflict?
#include <iostream>
#include <algorithm>
using namespace std;
int max(int a, int b)
{
return (a > b) ? a : b;
}
int main()
{
cout << max(5, 10) << endl;
}
So why isn't there any naming conflict?
You're declaring a non-template max, and std::max is a set of overloaded function templates, so they're all overloaded. And the non-template version declared in the global namespace is selected in overload resolution here.
F1 is determined to be a better function than F2 if implicit
conversions for all arguments of F1 are not worse than the implicit
conversions for all arguments of F2, and
...
or, if not that, F1 is a non-template function while F2 is a
template specialization
...
And by using namespace std I'm importing the function to the global namespace
This is a common misconception. Nothing is imported. In fact, placing the directive using namespace std; in the global namespace means that when a name is looked up in the global namespace, that name is also looked up in namespace std.
The std::max function is still in the namespace std, it is not in the global namespace.
Your declaration of max is fine as you are declaring ::max which is a separate entity to std::max.
When you make the unqualified function call max, the name is looked up in the global namespace, and also in namespace std.
The results of both of those lookups lead to an overload set consisting of all signatures of functions called ::max and std::max.
Then overload resolution selects the best match out of the overload set for the arguments provided, and it turns out that ::max is a better match because a non-template function is a better match than a function template, all other things being equal.

Why can't I use foo::bar functions within sub::bar when using namespace foo?

Consider the following program:
namespace foo {
namespace sub {
int f();
} // namespace sub
} // namespace foo
namespace bar {
namespace sub {
int g() {
using namespace foo;
return sub::f() + 1;
}
} // namespace sub
} // namespace bar
I expect this to compile, but - it doesn't:
$ g++-6 -c a.cpp
a.cpp: In function ‘int bar::sub::g()’:
a.cpp:12:9: error: ‘f’ is not a member of ‘bar::sub’
return sub::f() + 1;
^~~
a.cpp:12:9: note: suggested alternative:
a.cpp:3:5: note: ‘foo::sub::f’
int f();
^
no luck with clang either:
$ clang++-6.0 -c a.cpp
a.cpp:12:9: error: no member named 'f' in namespace 'bar::sub'; did you mean 'foo::sub::f'?
return sub::f() + 1;
^~~~~~
foo::sub::f
a.cpp:3:5: note: 'foo::sub::f' declared here
int f();
^
1 error generated.
and it knows which function I want, too!
Now, I understand that things could be ambiguous if I had both a foo::sub::f and a bar::sub::f here. But - why is bar::sub "hiding" foo::sub even when I explicitly ask to use foo::sub functions?
To be clear about what an answer might:
An explanation why this is the (most) reasonable behavior and my expectation is unreasonable.
The rationale for it being this way in the C++ standard.
A quotation from standard saying this needs to be the case; maybe the context will help me understand why this was decided.
Motivation: I've written my code so that the last namespace before the function is part of the method name, in the sense that you wouldn't understand what the function does without prepending the namespace. So instead of saying sub_f() like I would in C, I want to be able to say sub::f(). It's proving difficult to do so without prepending a much longer path of namespaces.
[namespace.udir] says (emphasis mine):
-2- A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. 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. [Note: In this context, “contains” means “contains directly or indirectly”. — end note]
In your example "the names in the nominated namespace" is just foo::sub because that's the only name declared in namespace foo, and the "nearest enclosing namespace which contains both the using-directive and the nominated namespace" is the global namespace. So foo::sub appears (for the purposes of name lookup) as though it were in the global namespace, like this:
namespace sub {
int f();
} // namespace sub
namespace bar {
namespace sub {
int g() {
return sub::f() + 1;
}
} // namespace sub
} // namespace bar
Now it should be more obvious that sub::f won't find anything. Name lookup for sub::f starts by looking for sub. It doesn't find it in the enclosing namespace (which is bar::sub) so it looks in the next innermost enclosing scope (which is bar) and there it finds sub. At that point name lookup for sub stops, it doesn't look in the global namespace where it would find foo::sub made visible by the using-directive.
The next step of name lookup tries to find f in the scope it found for sub, but there's no f in the namespace it found, so name lookup fails.
Using-directives do not work like adding a using-declaration for every member of the namespace, they are "weaker" than using-declarations. The reason for that is so that names really declared in a namespace take priority over names simply made visible by a using-directive. rodrigo's answer to a related question explains that in more detail.
I think the relevant part of the standard that prevents what you are trying to do is this:
6.3.10 Name hiding [basic.scope.hiding]
...
4 During the lookup of a name qualified by a namespace name, declarations that would otherwise be made visible by a using-directive can be hidden by declarations with the same name in the namespace containing the using-directive;
You have sub in both foo and bar namespaces. And the sub in bar is hiding the sub in foo in spite of the using directive. And that is the reason why the f() in foo::sub is also not visible.
An answer to your first point:
What happens when you add to your program a:
namespace sub
{
int f();
}
What should now the compiler choose:
::sub::f() or (using ::foo::)sub::f() ?

Why does the name lookup does not stop when it finds the entity implicitly declared by using directive?

Here is the code example:
#include<iostream>
using namespace std;
namespace B
{
int ohoh=2;
}
namespace A
{
int ohoh=666;
namespace C
{
//using B::ohoh;(as if declared by using directive) //why does the lookup not stops here?
int foo()
{
using namespace B;
cout<<ohoh<<endl;
}
}
}
int main()
{
A::C::foo();
}
The output is 666 but not 2. Why?
Quoted from cppref
For an unqualified name, that is a name that does not appear to the right of a scope resolution operator ::, name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined. (Note: lookup from some contexts skips some declarations, for example, lookup of the name used to the left of :: ignores function, variable, and enumerator declarations, lookup of a name used as a base class specifier ignores all non-type declarations)
For the purpose of unqualified name lookup, all declarations from a namespace nominated by a using directive appear as if declared in the nearest enclosing namespace which contains, directly or indirectly, both the using-directive and the nominated namespace.
From the quoted paragraph above ,the name lookup should stop at nearest namespace C ,Where I've commented in the code.Why does it does not stop and find A::ohoh ?
By the way,I think I should use the using directive as little as possible.
For the purpose of unqualified name lookup, all declarations from a namespace nominated by a using directive as if declared in the nearest enclosing namespace which contains [...] both the using-directive and the nominated namespace.
In this case, the nearest namespace that contains both B and the using-directive is the global namespace. Therefore, all names from B appear inside A::C::foo as if they were declared in the global namespace. When searching for the name ohoh, A is searched before the global namespace, so A::ohoh is the first declaration found and name lookup stops there.

Is "using namespace" transitive in C++?

To my astonishment the following code compiles and prints "X" on VC++ 2017:
#include <string>
#include <iostream>
namespace A {
using namespace std;
}
namespace B {
using namespace A;
}
namespace C {
using namespace B;
string a;
}
int main()
{
C::a = "X";
std::cout << C::a;
return 0;
}
It looks like the using namespace std works from namespace A through namespace B into namespace C.
Is this a bug in Visual C++ or does it concur with the language specification?
I had expected that using namespace std ends at the end of the enclosing scope wich is at the end of the definition of namespace A.
EDIT: I understand that the accepted answer to this question also answers my question. But that post is more about anonymous namespaces, while this one is about the transitivity of the using namespace directive. So I think it s a better example and the question makes sense.
Yes:
[C++14: 7.3.4/4]: For unqualified lookup (3.4.1), the using-directive is transitive: if a scope contains a using-directive that nominates a second namespace that itself contains using-directives, the effect is as if the using-directives from the second namespace also appeared in the first. [..]
So, the compiler is correct; using namespace here effectively imports the names into the enclosing namespace:
[C++14: 7.3.4/2]: A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. [..]
The "scope" here is that of the namespace; the contents of a scope doesn't vanish just because a } is encountered. Familiarity with block scopes sometimes makes it feel that way, though.