Interesting behavior of compiler with namespaces
This works for the function call expression:
f(a);
because the namespace that X::A
belongs to is included in the lookup for the function f
due to argument dependent lookup(ADL), cppreference explains ADL as follows:
Argument-dependent lookup, also known as ADL, or Koenig lookup, is the
set of rules for looking up the unqualified function names in
function-call expressions, including implicit function calls to
overloaded operators. These function names are looked up in the
namespaces of their arguments in addition to the scopes and namespaces
considered by the usual unqualified name lookup.Argument-dependent lookup makes it possible to use operators defined
in a different namespace
This is covered in the draft C++ standard section 3.4.2
Argument-dependent name lookup:
When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered
during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope
friend function or function template declarations (11.3) not otherwise visible may be found
and goes on to say:
For each argument type T in the function call, there is a set of zero or more associated namespaces and a
set of zero or more associated classes to be considered. The sets of namespaces and classes is determined
entirely by the types of the function arguments (and the namespace of any template template argument).
and includes the following bullet:
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a
member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces
of which its associated classes are members.[...]
and further down provides a similar example to your problem:
namespace NS {
class T { };
void f(T);
void g(T, int);
}
NS::T parm;
void g(NS::T, float);
int main() {
f(parm); // OK: calls NS::f
extern void g(NS::T, float);
g(parm, 1); // OK: calls g(NS::T, float)
}
The function call expression:
g(5);
does not work because ADL does not add any namespaces for arguments that are fundamental types.
Herb Sutter covers ADL in Gotw #30 and in What's In a Class? - The Interface Principle.
Namespaces confusion
The using directive modifies name lookup in a way that isn't exactly intuitive to most programmers. The standard says this in [namespace.udir]p2:
During unqualified name lookup (3.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.
This wording means that names from the namespace do not appear in the current scope, but in some outer scope. In your example the using directive is in the function which is in the global namespace, and the Jill is also in the global namespace, so the names from Jill appears as if they are in the global namespace. (As Joachim said, the names aren't actually introduced there, so they don't immediately conflict with existing names and you only get ambiguous lookups when you actually use them.)
This is a simple case and the compiler gives you an error, which is good. It can actually get more complicated than that.
namespace Outer {
namespace Mid1 { int i = 1; }
namespace Mid2 {
namespace Tricky {
int i = 2;
namespace Inner {
void f() {
using namespace Mid1;
std::cout << i;
}
}
}
}
}
This will output 2, not 1, even though you had the using directive right next to the line referring to i. But the nearest enclosing namespace that contains both Mid1
and the using directive is Outer
, so Mid1::i
acts as if it was declared in Outer
. If you had an Outer::i
it would be shadowed by Tricky::i
, and Mid1::i
fares no better.
An easy solution is to ban using directives and only use using declarations and namespace aliases. They're far more intuitive.
odd behavior of c++ namespace
The feature that is confusing you is called ADL (argument dependent lookup)
From cppreference:
Argument-dependent lookup, also known as ADL, or Koenig lookup, is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators. These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.
Argument-dependent lookup makes it possible to use operators defined in a different namespace.
In your example a2
being from the namespace ns
is enough for the compiler to also consider ns
when looking for print
.
The interesting part of your example is that int_type
is also coming from ns
, though it is just a typedef and int
is not declared in ns
. Consider that a typedef does not introduce a new type (rather an alias). So a2
really is an int
.
PS: This is not specific to Visual studio. Any compiler conforming to the standard should accept the code posted.
Why is using namespace std; considered bad practice?
Consider two libraries called Foo and Bar:
using namespace foo;
using namespace bar;
Everything works fine, and you can call Blah()
from Foo and Quux()
from Bar without problems. But one day you upgrade to a new version of Foo 2.0, which now offers a function called Quux()
. Now you've got a conflict: Both Foo 2.0 and Bar import Quux()
into your global namespace. This is going to take some effort to fix, especially if the function parameters happen to match.
If you had used foo::Blah()
and bar::Quux()
, then the introduction of foo::Quux()
would have been a non-event.
Namespace-scoped template function becomes visible in another namespace
That's argument-dependent lookup (ADL), also known as Koenig lookup.
In short, use of an operator or unadorned function call will find names in the enclosing namespaces of the operands or arguments.
Compiler behavior with const static non integral data initialization, namespace vs struct
Moreover, I think that this small example of namespace misuse could help us to shed some light on your first question (at least for the namespace case):
StaticNamespace.hpp:
#pragma once
namespace StaticNamespace
{
static double d = 1.0;
}
Class.hpp:
#include "StaticNamespace.hpp"
#include <iostream>
class Class
{
public:
#if 1
Class();
void printFromSource() const;
#else
Class(){
StaticNamespace::d = StaticNamespace::d + 0.1;
}
#endif
void printFromHeader() const { std::cout<<"Class from header "<<StaticNamespace::d<<" "<<&StaticNamespace::d<<std::endl; }
static void printDouble() { std::cout<<"Class static "<<StaticNamespace::d<<" "<<&StaticNamespace::d<<std::endl; }
};
Class.cpp:
#include "Class.hpp"
Class::Class()
{
StaticNamespace::d = StaticNamespace::d + 0.1;
}
void Class::printFromSource() const
{
std::cout<<"Class from source "<<StaticNamespace::d<<" "<<&StaticNamespace::d<<std::endl;
}
main.cpp:
#include <iostream>
#include "Class.hpp"
int main ()
{
Class test_class;
test_class.printFromHeader();
#if 1
test_class.printFromSource();
#endif
Class::printDouble();
}
If you set the preprocessor ifs to true you will have 2 translation units, otherwise there will be just one. As you can see the different behavior of the code in the two cases is compatible to the fact that each translation unit in this example owns an independent copy of the static variable. This is just a trivial example of course...
c++17 namespaces, is it possible to force qualified access ALWAYS?
A) is there any way to prevent all objects in a namespace to be blind to its fellow constituents, and to require access always through :: ?
There isn't.
B) if not, what would be the correct coding practice to obtain the desired behavior?
Use a class
.
C) if not, an alternative solution would be to separate the aaa namespace into 2, one for functions and another for variables, like f_aaa and v_aaa. but this seems quite clunky and ugly in practical use, eg. void f_sqlite::myfun() { v_sqlite::myvar; } instead of just void sqlite::myfun() { sqlite::myvar; }
Use a class
to group relevant functions and data together. What You want to hide put in a private
section.
Why does endl(std::cout) compile
This behavior is called argument dependent lookup or Koenig lookup. This algorithm tells the compiler to not just look at local scope, but also the namespaces that contain the argument's type while looking for unqualified function call.
For ex:
namespace foo {
struct bar{
int a;
};
void baz(struct bar) {
...
}
};
int main() {
foo::bar b = {42};
baz(b); // Also look in foo namespace (foo::baz)
// because type of argument(b) is in namespace foo
}
About the piece of code referred in question text:
endl
or std::endl
is declared in std
namespace as following:
template< class CharT, class Traits >
std::basic_ostream<charT,traits>& endl( std::basic_ostream<CharT, Traits>& os );
or
std::ostream& endl (std::ostream& os);
And cout
or std::cout
is declared as
extern std::ostream cout;
So calling std::endl(std::cout);
is perfectly fine.
Now when one calls just endl(std::cout);
, because the type of argument cout
is from std namespace
, unqualified supposedly a function endl
is searched in std
namespace and it is found succesfully and confirmed to be a function and thus a call to qualified function std::endl
is made.
Further reading:
GOTW 30: Name Lookup
Why does 'std::endl' require the namespace qualification when used in the statement 'std::cout << std::endl;", given argument-dependent lookup?
Related Topics
Fastest Way to Get the Integer Part of Sqrt(N)
What Should I Know About Structured Exceptions (Seh) in C++
Implicit VS Explicit Conversion
Static and Dynamic/Shared Linking with Mingw
How Are User-Level Threads Scheduled/Created, and How Are Kernel Level Threads Created
<Random> Generates Same Number in Linux, But Not in Windows
Lambda Functions as Base Classes
How to Easily Make Std::Cout Thread-Safe
Clang C++ Cross Compiler - Generating Windows Executable from MAC Os X
Is There a Compact Equivalent to Python Range() in C++/Stl
Std::Vector Reserve() and Push_Back() Is Faster Than Resize() and Array Index, Why
Should I Use Public or Private Variables
Use-Cases of Pure Virtual Functions with Body
Getting an Array of Bytes Out of Windows::Storage::Streams::Ibuffer