Is "using namespace" transitive in C++? - 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.

Related

Scope of `using namespace` in Unnamed Namespace

Why is the using directive using namespace std; in when enclosed in an anonymous namespace behaves as if it appeared at global scope?
#include <iostream>
namespace x
{
using namespace std;
void g()
{
cout << 1;
}
}
int main()
{
cout << 1; // compiles fine if `namespace x` is replaced with `namespace`
}
An unnamed namespace is equivalent to essentially writing:
namespace __compiler_generated_unique {
}
using namespace __compiler_generated_unique;
So it's like having a using directive at global scope. And using directives are transitive.
For a normative reference, here it is from n4861 (The C++20 standard draft):
[namespace.unnamed]
1 An unnamed-namespace-definition behaves as if it were replaced
by
inline namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }
where inline appears if and only if it appears in the
unnamed-namespace-definition and all occurrences of unique in a
translation unit are replaced by the same identifier, and this
identifier differs from all other identifiers in the translation unit.
The optional attribute-specifier-seq in the
unnamed-namespace-definition appertains to unique.
[namespace.udir]
4 For unqualified lookup ([basic.lookup.unqual]), 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.

using directive and function overloading in a namespace [duplicate]

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

Global unnamed namespace ambiguity vs nested unnamed namespace ambiguity

Consider the following two code snippets:
Snippet A
#include <iostream>
namespace
{
bool foo = false;
}
bool foo = true;
int main()
{
std::cout << foo << std::endl;
}
Snippet B
#include <iostream>
namespace A
{
namespace
{
bool foo = false;
}
bool foo = true;
}
int main()
{
std::cout << A::foo << std::endl;
}
In Snippet A, foo's usage inside int main() is ambiguous, whilst in Snippet B it is not. Why is this the case?
Related: Anonymous Namespace Ambiguity
The behavior of unnamed namespaces is specified in §7.3.1.1 [namespace.unnamed]/p1:
An unnamed-namespace-definition behaves as if it were replaced by
inline_opt namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }
where inline appears if and only if it appears in the
unnamed-namespace-definition, all occurrences of unique in a translation unit are replaced by the same identifier, and this
identifier differs from all other identifiers in the entire program.
In particular, note that the declarations inside the unnamed namespace is made visible in the surrounding scope via a using-directive using namespace unique;.
In Snippet A, foo is unqualified, so the compiler performs unqualified name lookup (§3.4.1 [basic.lookup.unqual]). Relevant here is paragraph 2 of the subclause:
2 The declarations from the namespace nominated by a using-directive
become visible in a namespace enclosing the using-directive; see
7.3.4. For the purpose of the unqualified name lookup rules described in 3.4.1, the declarations from the namespace nominated by the
using-directive are considered members of that enclosing namespace.
Hence, unqualified name lookup finds both declarations of foo, and the name is ambiguous.
In Snippet B, A::foo is qualified, so qualified name lookup rules apply. Since A is a namespace, the applicable subclause is §3.4.3.2 [namespace.qual]. As relevant here, the rule is specified in paragraph 2 of that subclause:
For a namespace X and name m, the namespace-qualified lookup set
S(X,m) is defined as follows: Let S'(X,m) be the set of all
declarations of m in X and the inline namespace set of X
(7.3.1). If S'(X,m) is not empty, S(X,m) is S'(X,m); otherwise,
S(X,m) is the union of S(Ni,m) for all namespaces Ni nominated
by using-directives in X and its inline namespace set.
In other words, qualified name lookup considers namespaces nominated by using-directives only if the name is not found in the specified namespace and its inline namespace set. Here, the name foo is found in namespace A, so the unnamed namespace nominated by the using-directive is not considered, and there's no ambiguity.
If you write ::foo instead of foo in Snippet A, then qualified lookup rules would apply instead, and there would once again be no ambiguity.

Ambiguous reference to namespace within an inline namespace

Assume the following code:
namespace test
{
namespace detail
{
}
inline namespace v1
{
namespace detail
{
void foo()
{
}
}
}
}
int main()
{
test::detail::foo();
}
As we can see, this code compiles with Clang; not with GCC, however - GCC complains that the reference to namespace detail is ambiguous:
main.cpp:20:11: error: reference to 'detail' is ambiguous
test::detail::foo();
^
main.cpp:4:5: note: candidates are: namespace test::detail { }
{
^
main.cpp:10:9: note: namespace test::v1::detail { }
{
^
Which compiler does the correct thing here?
GCC is correct:
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 (3.4.2) whenever one of them is, and a using-directive that names the namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (7.3.1.1). Furthermore, each member of the inline namespace can subsequently be explicitly instantiated (14.7.2) or explicitly specialized (14.7.3) as though it were a member of the enclosing namespace. Finally, looking up a name in the enclosing namespace via explicit qualification (3.4.3.2) will include members of the inline namespace brought in by the using-directive even if there are declarations of that name in the enclosing namespace.
(This is at 7.3.1/8 in old n3337 numbering)
I believe you're seeing Clang bug #10361.
GCC is correct.
N3797 states that,
and a using- directive (
7.3.4 ) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (
7.3.1.1 ).
Thus, test::detail is not the same namespace as test::v1::detail, so the lookup of test::detail is ambiguous. The Standard is exceptionally clear that the lookup of test::detail should include test::v1::detail, there are many quotes in this section to support this, but nothing to state that they should be considered the same namespace.
Arguably, I would say that Clang's behaviour is superior, but GCC's is correct.

Unqualified name lookup finds inline namespace member

I've written the following code:
#include <iostream>
inline namespace M
{
int j=42;
}
int main(){ std::cout << j << "\n"; } //j is unqualified name here.
//Hence, unqualified name lookup rules will be applied.
//This implies that member of inline namespace shall not be considered.
//But it is not true
And it works fine. But I'm expected that the that program is ill-formed. It is because the Standard said (N3797, sec. 7.3.1/7):
Finally, looking up a name in the enclosing namespace via explicit
qualification (3.4.3.2) will include members of the inline namespace
brought in by the using-directive even if there are declarations of
that name in the enclosing namespace.
Also the section 3.4.1/6 does not said anything about involving of inline namespace in the unqualified name lookup:
A name used in the definition of a function following the function’s
declarator-id 28 that is a member of namespace N (where, only for the
purpose of exposition, N could represent the global scope) shall be
declared before its use in the block in which it is used or in one of
its enclosing blocks (6.3) or, shall be declared before its use in
namespace N or, if N is a nested namespace, shall be declared before
its use in one of N’s enclosing namespaces.
It is a g++ bug or I understood that rules incorrectly?
There's no bug..
No, it's not a bug in neither g++ (or clang++) which has the behavior described, the compiler is supposed to find j.
inline namespace N {
int j;
}
int main () {
int a = j; // legal, `j` == `N::j`
}
What does the Standard say?
You are missing a very important section of the standard, namely 7.3.1§8, where it states that the enclosing namespace of an inline namespace implicitly has a using directive that refers to the inline namespace.
[7.3.1]p8 namespace definition [namespace.def]
Members of an inline namespace can be used in most respects as thought 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 (3.4.2) whenever one of them is, and a using-directive (7.3.4) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (7.3.1.1).
Elaboration
This means that our previous example is semantically equivalent to the below, where we have introduced a using-directive to bring the names from our nested namespace into the global namespace:
inline namespace N {
int j;
}
using namespace N; // the implicit using-directive
int main () {
int a = j; // legal
}