This seems a little backwards to me but it works:
#include <iostream>
namespace nTest
{
struct cTest {};
void fTest(cTest& x)
{
std::cout << "nTest::fTest(cTest&) called" << std::endl;
}
}
int main(void)
{
nTest::cTest x;
fTest(x); //Weird! fTest is resolved since its parameter belongs to nTest.
return 0;
}
Normally, you would need nTest:: in order to access fTest, but its parameter which belongs to nTest appears to add nTest to the list of possible scopes in which to search for fTest. It seems odd to me that the parameter scope influences the function lookup.
This compiles fine in GCC, but I'm wondering is this usage portable? What is the official definition of this scoping mechanism?
That is ADL (Argument Dependent Lookup) or Koenig Lookup (for the designer of the feature). The purpose of the feature is that in many cases the same namespace will contain types and functions that can be applied to those types, all of which conform the interface. If ADL was not in place, you would have to bring the identifiers into scope with using declarations or you would have to qualify the calls.
This becomes a nightmare since the language allows for operator overloads. Consider the following example:
namespace n {
struct test {};
test operator+( test, test const & ); // implemented
};
int main() {
n::test a,b;
n::test c = a + b; //without ADL: c = n::operator+( a, b )
}
While it might seem like an awkward situation, consider that n might be the std namespace, test might be ostream, and operator+ could be operator<<:
int main( int argc, char** ) {
std::cout << "Hi there, there are " << argc << " arguments" << std::endl;
}
Without ADL, the calls to operator<< would have to be explicit, and moreover you would have to know which of them is implemented as a free function versus a method. Did you know that std::cout << "Hi" is calling a free function and std::cout << 5 is calling a member function? Not many people realize it, and seriously, almost no one cares. ADL hides that from you.
It is called Koenig aka Argument dependent lookup http://en.wikipedia.org/wiki/Argument-dependent_name_lookup
It was originally designed to find overloaded operators, like the operator<< you use to send a string to std::cout. If we didn't have ADL, you would have had to write your code like this instead: std::operator<<(std::cout, "nTest::fTest(cTest&) called").
Not too nice!
And if it works for operators, why not work the same way for functions?
Related
I would like to overload operator<<(std::ostream&, std::chrono::duration<std::uint64, std::nano>) - and ideally without requiring users to write using statements everywhere.
What's the best practice here?
Context...
// Replace code like this:
using Time = std::uint64_t;
void example(Time ts) {
if (ts) { std::cout << ts; }
}
// with code like this:
using Time = std::chrono::duration<std::uint64_t, std::nano>;
void example(Time ts) {
if (!!ts) { std::cout << ts; }
}
// this 'works for me'; but it is not allowed to add overloads to `namespace std`
// The type `Time` can be used in any other namespace, and the operators are found by ADL
namespace std {
ostream& operator<<(ostream&, chrono::duration<uint64_t, nano>);
bool operator!(chrono::duration<uint64_t, nano>);
}
Is there a way to get the effect of placing the overloads in the std namespace without breaking the rules on extending namespace std?
You put it in the global namespace. Any function outside of namespace std that does name lookup for << will find your overload, and prefer it to the one defined in C++20.
Afaict, the only place where this fails is std::ostream_iterator, as that is the only call to << within namespace std.
See it on coliru
In the code below, it looks quite obvious that the function definition for myFn with two arguments should come from namespace N. But the compiler fails to compile it. Is it a compiler (g++ 8.3) limitation, or imposed by the C++ standard?
#include <bits/stdc++.h>
using namespace std;
namespace N
{
// Same name function exists in class A
void myFn(int a, int b)
{
cout << a << ' ' << b << endl;
}
}
using namespace N;
class A {
public:
void myFn(int a)
{
#ifdef FINE
// Explicitly specify where should myFn definition come from
N::myFn(a, a);
#else
myFn(a, a);
#endif
}
};
int main()
{
A a;
a.myFn(3);
return 2;
}
It's intended. Name lookup stops at the scope where the name is found. The mechanism makes sure your code behaves the same even if functions are added or removed from the enclosing scopes.
Otherwise, changing N's members would risk breaking enclosed classes and namespaces. Consider the potential disasters if one adds a free function that is a better match in overload resolution compared to another class member. If it wasn't ignored, the behavior of the class could change by accident!
This example should illustrate the issue:
namespace ns {
// void foo(int) { std::terminate(); }
struct C {
void foo(char) {}
C() {
foo(0);
}
};
}
Under the current rules, uncommenting foo will have no adverse effects. But if name lookup did consider it, because 0 is an int and must be converted to a char, constructing a C would abort the program! That's drastic and easy to spot. But in a real 100M LOC program, misbehaving name lookup could cause bugs that are much more sinister and harder to catch.
This is solely for example I happen to notice with!
I'm using cout with operator<< and why won't this program compile?
Why aren't they being considered the way function overloadings are?
#include <iostream> // imports the declaration of std::cout
using namespace std; // makes std::cout accessible as "cout"
int cout() // declares our own "cout" function
{
return 5;
}
int main()
{
cout << "Hello, world!"; // Compile error!
return 0;
}
At the point of the attempted stream insertion, there are two names cout in global scope: one from the standard library, std::cout, pulled into global scope by that infernal using declaration, and one defined as a function int cout(). In the expression
cout << "Hello, world!\n";
the use of cout is ambiguous. There is no function overloading for two reasons: first, std::cout is not a function, so would not take part in overloading. But more fundamentally, the use of cout in that expression is not a function call, so, again, there is no overloading. The name cout from the function definition is treated as a pointer to function, and the name cout from namespace std is the name of an object. There are two possible interpretations of that name, so its use in that << expression is ambiguous.
#include <iostream>
#include <string>
class X {};
namespace N
{
std::string to_string(X)
{
return "foo";
}
void foo()
{
//using std::to_string; // will break the build if uncommented...
//using N::to_string; // ...unless this is uncommented as well
std::cout << to_string(X()) << std::endl;
}
}
int main()
{
N::foo();
return 0;
}
Either I have stumbled upon one of the many C++ arcana I do not master, or I am missing something obvious here.
How can using std::to_string apparently reduce the set of names available during unqualified lookup to only those reachable via ADL? While I can guess the problem might be that to_string(X) is declared in a different namespace than X, I cannot help but notice that, without using std::to_string, N::to_string(X) is simply available to N::foo() by using the "normal", intuitive lookup rules I am accustomed to.
This is not specific to a using-declaration, but follows normal scoping rules. When you introduce a name into the function, that hides equally named things from outer scopes.
You could just as well have an int to_string; local variable in foo. That would also hide N::to_string.
I have two namespaces that each have a function with the same name. If from one of the namespaces I want to call the function that matches the best. From a function in NamespaceA, if I call MyFunction(...), of course it uses the one in NamespaceA. However, if I add a 'using NamespaceB::MyFunction', I would then expect the behavior I described. However, what I actually see is that it ALWAYS finds the NamespaceB function, even though I am in NamespaceA. HOWEVER, if I ALSO add a using::NamespaceA (even though I am already in NamespaceA), it works as I'd expect. A demonstration is below. Can anyone explain how this works?
#include <iostream>
namespace NamespaceA
{
void DoSomething();
void MyFunction(int object);
}
namespace NamespaceB
{
void MyFunction(float object);
}
namespace NamespaceA
{
void DoSomething()
{
using NamespaceA::MyFunction; // Note that without this line the lookup always fins the NamespaceB::MyFunction!
using NamespaceB::MyFunction;
MyFunction(1);
MyFunction(2.0f);
}
void MyFunction(int object)
{
std::cout << "int: " << object << std::endl;
}
}
namespace NamespaceB
{
void MyFunction(float object)
{
std::cout << "float: " << object << std::endl;
}
}
int main(int argc, char *argv[])
{
NamespaceA::DoSomething();
return 0;
}
It has to do with the order in which different parts of the program are looked in to find a name. For the situation you mention, it has to do with the scope of the function's top-level block being searched for before the enclosing namespace. Basically, the using declaration brings that name into the top-level scope of DoSomething, and since that scope is looked in before the enclosing namespace scope, then if a matching function is found there, then the enclosing namespace scope isn't considered.
I have glossed over a lot of stuff that isn't relevant in your example (for example, if the argument were not a built-in type then, believe it or not, names from the scope where that type was defined could be considered as well. For the whole story, see section 3.4 here. It's pretty scary, about 13 pages to describe all this stuff; but don't bother with it unless you really are curious, because most of the stuff is there so that it "works the way you expect", more-or-less. That document is not the real Standard but actually a working draft with some corrections, so it is basically the real C++ Standard plus some bugfixes.
i believe namespaces use the same scoping rules as variables. so if you have a local namespace, lookups will happen there first before moving to the outer scope.
i'm not sure what the rules are for the situation where you have imported two namespaces with the same function names, but you should always fully qualify the function calls in that scenario just for clarity, instead of relying on some nuance of the language implementation for namespaces that people may not be familiar with.
Short answer: Local defined name and the name declared by a using-declaration hides nonlocal names.
Detailed answer:
Your question is very interesting. I didn't open standarts of C++98,03,11 for that question, but open Bjarne Stroustrup's book
Namespace - is a named scope. Verbosity can be eliminated using two techniques:
create synonymous with using NS :: x; (using-declaration)
create synonymous for all the variables with using namespace NS :: x; (using-directive)
The answer to your question is here:
Appendix B 10.1
local definitions, and names defined with using-declaration hides
the name of a non-local definitions.
Bonus with opposite situation:
Also if you
using NamespaceA::MyFunction;
using NamespaceB::MyFunction;
change to
using namespace NamespaceB;
Then you due to text below get situation with call only void MyFunction(int object)
8.2.8.2
Names explicitly declared in namespace (also made with using declaration)
have priority over the names made available by using directives
Extra code to play with:
#include <iostream>
// var in global namespace
const char* one = "G_one";
// vars in named namespace
namespace NS1 {
const char* one = "NS1_one";
const char* two = "NS1_two";
const char* three = "NS1_three";
}
namespace NS2 {
const char* one = "NS2_one";
const char* two = "NS2_two";
const char* three = "NS2_three";
}
int main(int argc, char *argv[])
{
using namespace NS1; // using-directive
using namespace NS2; // using-directive
// const char* two = "L_two"; // local namespace
using NS2::two; // using-declaration
// C++ rules
// Local names and names with using-declarations
// takes precedence over the name of the NS
std::cout << "two: " << two << std::endl;
//std::cout << "three: " << three << std::endl; // ambiguous symbol
// But the name in global-namespace does not have priority over imported name from namespace
//std::cout << "one: " << one << std::endl; // ambiguous symbol. Because wGlobal names does not have priority over
return 0;
}