I have a question regarding the standard ADL resolution in C++.
Here is a sample code explaining my enquiry:
#include <string>
// The mechanism:
namespace A {
template< class C >
::std::string scope(const C*)
{ return "A"; }
namespace B {
template< class C >
::std::string scope(const C *foo)
{ return A::scope(foo)+"::B"; }
} // namespace B
} // namespace A
::std::string scope(...)
{ return ""; }
// The test classes
struct foo {};
namespace A {
struct foo {};
namespace B {
struct foo {};
}
}
// The usage
int main()
{
foo *Foo=0;
A::foo *FooA=0;
A::B::foo *FooB=0;
scope(Foo); // OK, returns ""
scope(FooA); // OK, returns "A"
scope(FooB); // On one compiler, OK returns "A::B" ; On another, compiler error "Ambiguous call" between A::scope() and A::B::scope()
}
So, my question is what is the standard regarding ADL?
Should all the functions from parent namespaces of the argument be found, or only the functions available in the (nested) namespace of the argument + the global functions?
This program has been tested on MSVC 2008 (and compiles with SP but not without...)
According to the standard, ADL works (modulo a couple of special rules)
"as if" the function name were preceded by the namespace; in your last
line, lookup should precede as if you'd written A::B::scope. Which
does not look in the surrounding namespaces.
Note that even within namespace A::B, there would be no ambiguity; in
A::B, A::B::scope hides A::scope. Unqualified name lookup stops
in the scope where it first finds the name.
Related
I just noticed this. I don't know why this is the case, if i use one element from a namespace i don't want anything else to be accessible without having to use the namespace. For example here, this code is valid:
namespace Test
{
struct Magic
{
int poof;
};
struct Magic2
{
int poof;
};
int Alakazam(const Magic& m)
{
return m.poof;
}
int Alakazam(const Magic2& m)
{
return m.poof;
}
};
using Magic = Test::Magic;
int main()
{
Alakazam(Magic()); // valid
Alakazam(Test::Magic2()); // valid
Test::Alakazam(Magic()); // what i want to only be valid
Test::Alakazam(Test::Magic2()); // this too
}
Any reasoning behind this? Does the spec state that this has to be true?
As suggested by immbis in the comment, this is defined by the standard:
3.4.2: Argument dependent name lookup
When the postfix-expression in a function call is an unqualified-id, other namespaces not considered during the usual
unqualified lookup may be searched, and in those namespaces,
namespace-scope friend function or function template declarations not
otherwise visible may be found. These modifications to the search
depend on the types of the arguments (and for template template
arguments, the namespace of the template argument).
...
If you want to defeat this mecanism, you have to use nested namespace like this, but it's tricky:
namespace Test
{
struct Magic
{
int poof;
};
struct Magic2
{
int poof;
};
namespace Test2 { // use a nested namespace that will not be searched autoamtically
int Alakazam(const Magic& m)
{
return m.poof;
}
int Alakazam(const Magic2& m)
{
return m.poof;
}
}
using namespace Test2; // but give some access to the enclosing namespace
};
Live Demo : Then, your two first calls will not be valid any longer. However, the last call in your example is still possible: you can't prevent the use of fully qualified names outside of the namespace.
So i have the following functions:
GraSys::CRectangle GraSys::CPlane::boundingBox(std::string type, std::string color)
{
CRectangle myObject = CRectangle(color);
return myObject;
}
Since boundingBox is part of the namespace GraSys and i have to use it in order to declare this function , why i don't need to do this inside the function?, why can i just use? why does it let me compile with out a problem ?
CRectangle myObject = CRectangle(color);
insted of :
GraSys::CRectangle myObject = GraSys::CRectangle(color);
Hope my question is not confusing.
You're implementing a function that is declared in the namespace of GrasSys. When you're in that function, you use the declaring name space.
For clarity, consider:
namespace GraSys {
class CRectangle { ... };
class CPlane {
... boundingBox(...); ...
}
void example(...) { ... };
}
When you implement boundingBox, you will be in the namespace declared during the declaration of the function, which is GraSys. CRectangle is declared within GraSys, so you can use it directly. Similarly, note that you can directly call functions as well, so in the above code, you can directly call example in your boundingBox implementation.
This is called unqualified name lookup. You can read the complete lookup rules in the C++ standard section 3.4.1 or in more human-readable form here.
Here is an example from the standard, which may be better than verbose explanations:
namespace A {
namespace N {
void f();
}
}
void A::N::f() {
i = 5;
// The following scopes are searched for a declaration of i:
// 1) outermost block scope of A::N::f, before the use of i
// 2) scope of namespace N
// 3) scope of namespace A
// 4) global scope, before the definition of A::N::f
}
using namespace is like add the name space to the global name space (i.e the :: name space). if you do it, from now on the compiler will look for each symbol in all the used name spaces.
Only in case there is ambiguity (mean a symbol with the same name declared in 2 used name spaces, you will be have to use the namespace for it.
namespace A{
void f();
void g();
}
namespace B{
void g();
}
using namespace A;
using namespace B;
A::f(); //always work
f(); //work since it is the only symbol named f
A::g();//always work
B::g();//always work
g();// error since g is ambiguous.
I am trying to create my own enum-based error category and want my enum with error codes to be defined inside some namespace. Much to my surprise this prevents the automatic conversion from values of my enum into std::error_code (such conversion works if the enum is defined in the global namespace).
#include <system_error>
namespace NS { enum class X {a,b,c}; }
using NS::X;
class X_category : public std::error_category
{
public:
virtual const char *name() const noexcept override { return "X"; }
virtual std::string message(int ev) const override { return ""; }
};
inline const std::error_category& X_category()
{
static class X_category c; return c;
}
template<> struct std::is_error_code_enum<X> : public std::true_type{};
inline std::error_code make_error_code(X result)
{
return std::error_code(static_cast<int>(result), X_category());
}
int main()
{
std::error_code e = X::a; // does not work !!
}
Am I missing something in my code above (related to overloading resolution rules perhaps) to make it work? Or do the enums for std::is_error_code_enum<> can only be defined inside a global namespace??
EDIT. My compiler (MSVC2013) does not complain about it but it seems the specialization of std::is_error_code_enum<> must be done inside std namespace. Also I added noexcept keyword on name() method to make the code even more C++11 compliant (MSVC2013 won't understand noexcept, but MSVC2015 will).
EDIT2. According to C++11 14.7.3.2 [temp.expl.spec]:
An explicit specialization shall be declared in a namespace enclosing the specialized template.
So it is not necessary to put specialization of std::is_error_code_enum<> inside an std namespace. MSVC compiles it correctly but GCC complains which is actually a bug in GCC since GCC acts by old C++03 rules which were more restrictive.
The constructor template from error_code is indeed considered in overload resolution - you correctly specialized is_error_code. The problem is the ADL in this line in the definition of error_codes constructor template:
*this = make_error_code(__e);
ADL does not consider the global namespace because X was only defined in NS, not the global one. [basic.lookup.argdep]/(2.3):
If T is an enumeration type, its associated namespace is the
innermost enclosing namespace of its declaration. [..]
The using declaration doesn't change this. [basic.lookup.argdep]/2:
The sets of namespaces and classes is determined entirely by the types
of the function arguments (and the namespace of any template template
argument).
Typedef names and using-declarations used to specify the types do not contribute to this set.
To fix this add your make_error_code to NS:
namespace NS {
inline std::error_code make_error_code(X result)
{
return std::error_code(static_cast<int>(result), X_category());
}
}
Demo.
I believe the problem is that most of that setup code needs to be inside a namespace. This code compiles and runs for me in ideone:
#include <system_error>
#include <iostream>
namespace NS {
enum X {a,b,c};
class X_category : public std::error_category
{
public:
virtual const char *name() const noexcept override { return "X"; }
virtual std::string message(int ev) const override { return "M"; }
};
inline std::error_code make_error_code(X result)
{
return std::error_code(static_cast<int>(result), X_category());
}
}
namespace std {
template<> struct is_error_code_enum<NS::X> : public true_type{};
}
int main()
{
std::cout << NS::X::a;
std::error_code e = NS::X::a;
std::cout << e.value();
}
Unfortunately I still can't make much sense out of system_error, so I can't explain why, for instance, using an enum class instead of just a plain enum gives me an unspecified runtime error.
Consider the following code:
#include <stdio.h>
class A
{
public:
friend void foo(A a){ printf("3\n"); }
};
int main()
{
foo(A());
}
It works. But I thought that this code is invalid. It is because 3.4.1/3:
For purposes of determining (during parsing) whether an expression is
a postfix-expression for a function call, the usual name lookup rules
apply.
Usual name lookup rules could not find the friend function because name declared by friend is invisible in the global namespace in my case. Actually 3.3.1/4:
friend declarations (11.3) may introduce a (possibly not visible) name
into an enclosing namespace
This implies that the programm is ill-formed. It is because that there is no name which found during the determining is the expression foo(A()); is a postfix-expression for a function call.
I'm confusing...
When parsing the following program
#include <iostream>
using namespace std;
typedef int foo;
class A
{
public:
operator int(){
return 42;
}
};
int main()
{
cout << foo(A());
}
the output will be 42 because 3.4.1/3
For purposes of determining (during parsing) whether an expression is
a postfix-expression for a function call, the usual name lookup rules
apply.
that means: to determine if foo is a postfix-expression (e.g. a cast) or a function call, the compiler will first use name lookup and search for it in the global namespace and/or enclosing scopes / base classes (or with fully qualified lookups if available).
Now take this code:
#include <iostream>
using namespace std;
class A
{
public:
friend int foo(A a){ return 55; }
operator int(){
return 42;
}
};
int main()
{
cout << foo(A());
}
The above will output 55 thanks to ADL: foo will be found by searching inside the scopes defined by its potential arguments, i.e. A.
A friend declaration introduces a (possibly not visible) name as you posted (3.3.1/4)
friend declarations (11.3) may introduce a (possibly not visible) name
into an enclosing namespace
that means the following code will not work
#include <iostream>
using namespace std;
class A
{
public:
friend int foo(A a){ return 55; }
operator int(){
return 42;
}
};
int main()
{
cout << ::foo(A()); // Not found
cout << A::foo(A()); // Not found
}
You might want to search for "friend name injection" and/or the Barton-Nackman trick.
Short story: now ordinary lookups can't find friend declarations.
So the code you posted is well-formed because ADL allows it to run as I explained in the previous passages.
For practice, I wrote some template functions whose names are the same as the stl algorithms. But my code can not compile
error: Call to < algorithm_name > is ambiguous.
I only included using std::necessary_names; in my code rather than using namespace std;.
Usually when you have using, the "used" name takes precedence:
namespace N { int x = 0; }
int x = 1;
int main() {
using N::x;
cout << x;
}
// Output: 0
However, Argument-Dependent Lookup can mess this up:
namespace N {
struct T {};
void f(T) {}
}
namespace M {
void f(N::T) {}
}
int main() {
using M::f;
N::T o;
f(o); // <--- error: call of overloaded 'f(N::T&)' is ambiguous
}
So, if you are having trouble, qualify your own namespace (in this example, M) explicitly:
namespace N {
struct T {};
void f(T) { cout << "N::f"; }
}
namespace M {
void f(N::T) { cout << "M::f"; }
}
int main() {
using M::f;
N::T o;
M::f(o); // <--- Output: "M::f"
}
In a somewhat bizarre twist, you can also use parentheses to prevent ADL:
namespace N {
struct T {};
void f(T) { cout << "N::f"; }
}
namespace M {
void f(N::T) { cout << "M::f"; }
}
int main() {
using M::f;
N::T o;
(f)(o); // <--- Output: "M::f"
}
Explanation
[n3290: 3.4.1/1]: [re: unqualified name lookup] In all the cases
listed in 3.4.1, the scopes are searched for a declaration in the
order listed in each of the respective categories; name lookup ends
as soon as a declaration is found for the name. If no declaration is
found, the program is ill-formed.
[n3290: 3.4.1/2]: [i.e. first priority] 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.
[n3290: 3.4.2/1]: [re: argument-dependent 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 declarations (11.3) not
otherwise visible may be found. These modifications to the search
depend on the types of the arguments (and for template template
arguments, the namespace of the template argument).
i.e. Normal lookup stops at the name that you brought into scope with using, but when ADL comes into play, other names are also added to the candidate set, causing an ambiguity between two names.
It's better to declare your own version in a namespace; so that such problem would not occur.
namespace MySTL
{
template<typename T, ... > // ... means other template params
class vector;
template<typename T, ... >
class queue;
...
}
now you can do,
using std::vector;
which will not collide with MySTL::vector.
Chances are that you are hitting a problem with Argument Dependent Lookup. When you pass a type that is defined within a namespace to an unqualified function, the namespaces of all the arguments are implicitly added to the lookup set, and that might cause collisions. You can try to qualify your own algorithm calls to inhibit ADL from kicking in.
namespace n {
struct test {};
void foo( test const & ) {}
};
int main() {
n::test t;
foo( t ); // Will find n::foo as the argument belongs to n namespace
}