Why do g++ and clang break the namespace abstraction in this case? - c++

This compiles:
struct str {};
namespace a
{
void foo(str s) {}
}
namespace b
{
void foo(str s) {}
void bar(str s) { foo(s); }
}
int main(int, char**)
{
return 0;
}
but this doesn't (with the struct definition moved inside namespace a)
namespace a
{
struct str {};
void foo(str s) {}
}
namespace b
{
void foo(a::str s) {}
void bar(a::str s) { foo(s); }
}
int main(int, char**)
{
return 0;
}
The error I get is
bad.cpp: In function ‘void b::bar(a::str)’:
bad.cpp:12: error: call of overloaded ‘foo(a::str&)’ is ambiguous
bad.cpp:10: note: candidates are: void b::foo(a::str)
bad.cpp:5: note: void a::foo(a::str)
It seems reasonable to expect that, since a::foo is not in scope, the call to foo can only refer to b::foo.
Is there a good reason for compilation to fail (and if so, what is it), or is it a deficiency in the implementations (of both major compilers)?

This is because of the way name lookup, and in particular Argument-Dependent Lookup (ADL), works. When deciding which functions may be a candidate for resolving your call, the compiler will first look up names in:
The namespace where the function call occurs;
The namespace(s) where the type(s) of the argument(s) is/are defined.
If no function with that name is found in those namespaces, the compiler will proceed inspecting parent namespaces of the namespace where the call is made.
So what is going on in the examples from your question?
In the first case, str is defined in the global namespace, and there is no function called foo() there. However, there is one in the namespace where the call occurs (b): so the compiler has found a valid name, name lookup stops, and overload resolution starts.
But well, there's only one candidate function! So the task is easy here: the compiler invokes b::foo().
In the second case, on the other hand, str is defined in the a namespace, and when calling foo(s), the compiler will again look in the namespace where the call is made (b) and in the namespace where the type of the argument (str) is defined - this time, a.
So now there are two functions with matching names for resolving the call: enter overload resolution! Alas, both functions are equally good (exact matches, no conversion required). Hence, the call is ambiguous.

Related

Why doesn't ADL work with functions defined outside of a namespace?

I know that my compiler in the example below will execute the function First::fun(), because of Argument-Dependent name Lookup (ADL)/Koenig lookup and in order to execute Second::fun() this needs to be explicitly called in the main function.
#include <iostream>
using namespace std;
namespace First
{
enum Enum
{
FIRST
};
void fun(First::Enum symbol)
{
cout << "First fun\n";
}
}
namespace Second
{
void fun(First::Enum symbol)
{
cout << "Second fun\n";
}
}
int main()
{
fun(First::FIRST); // Calls First::fun()
}
However, when adding another function fun() outside of the namespaces (see code below) and calling fun() without a prefixed namespace the compiler gives an ambiguity error. The functions inside the namespaces can still be called by explicitly prefixing the namespace, but fun() is unreachable. Why doesn't the compiler prefer the function outside of the namespaces when none are explicitly called? Is there a specific reason this behaviour is avoided?
// ^ Namespaces are still here
fun(First::Enum symbol)
{
cout << "No namespace fun\n";
}
int main()
{
fun(First::FIRST); // Doesn't compile: ambiguity!
}
EDIT
As Yksisarvinen rightfully pointed out, the global fun() can still be called by prefixing with the global namespace: ::fun(First::FIRST);.
However, this still leaves me with the question: Why doesn't the compiler prefer the global fun() in the ambiguous call?
Why doesn't the compiler prefer the global fun() in the ambiguous call?
The global fun is found by unqualified name lookup, and First::fun is found by ADL, both are put in overload set and overload resolution can't select one.
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.

Which look up rule prevents the compiler from finding the function?

void Foo(int i)
{
}
struct Bar
{
static void Foo() { Foo(1); }
};
The above code does not compile. It cannot find Foo(int). Why? I know it has to do with having the same function name, but did not get further understanding the problem.
Why do I need a qualified lookup?
From 3.4.1 (emphasis mine)
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.
In this particular case the first scope to be searched is the function local scope. Foo is not found there. Then comes the class scope. Since the name Foo is found in it, the name lookup stops there and the other Foo does not participate in overload resolution at all.
If a function in a particular namespace shares the same name as one in a global namespace, then the one in the global namespace is not found.
Unfortunately the C++ standard does not allow you to bring in the global namespace into the current one with an appropriate using statement, although you can use using ::Foo; to pull in that particular function:
void Foo(char)
{
}
struct Bar
{
static void Foo(double) { }
static void Foo() {
using ::Foo;
Foo('c'); // correct overload is found since ::Foo is pulled into scope
Foo(3.0);
}
};
Otherwise you need to use the scope resolution operator to find the global function:
struct Bar
{
static void Foo() { ::Foo(1); }
};

place utility routines be in the same namespace as the types it uses?

I've got a bunch of my own objects which I've dutifully put inside my own namespace:
namespace my { struct foo final {}; /* etc. */}
Where should I put non-member non-friend functions (i.e., "global" utility routines) which take my types as parameters? Should I also put them in the my namespace
namespace my { extern void f(const foo&); }
Or, is there an upside (or downside) to put them in the global namespace
extern void f(const my::foo&);
In either case, the argument to f is my::foo, so does it matter whether the function itself is actually named ::f() or my::f()?
Edit: note that I'm specifically not looking for "I like global" or "I like in the namespace" (or similar). Rather, I'm seeking specific technical reasons to prefer one approach over the other (assuming such differences actually exist). From a comment, it sounds like one (the?) factor to consider may be ADL behavior; are there others?
Putting operations tightly coupled to a type in the same namespace as the type permits Argument Dependent Lookup or Koenig lookup to work.
Polluting the global namespace is often a bad idea; you only get one global namespace, and if your code doesn't play with what someone else put there, there are few solutions.
For example, if you have a type or function named CString in the global namespace and you try to include and use MFC code which injects a CString into the global namespace, you are screwed.
Placing code in a namespace means you pollute the global namespace with one token, instead of one per function and type name (etc).
A second thing to consider is if your types are template generated, placing a friend function within the template results in an ADL-discoverable non-template function which is found when interacting with instances of the class instances of the template.
namespace my {
template<class T>
struct foo {
friend foo operator+( foo lhs, foo rhs ) { return {lhs.x+rhs.x}; }
friend foo add( foo lhs, foo rhs ) { return {lhs.x+rhs.x}; }
int x;
};
}
now my::foo f0{0},f1{1}; auto f2 = add(f0, f1); works, as does auto f3=f0+f1;.
Both add and operator+ here are not templates, which means if we have a type that converts-to-foo, add(f0, converts_to_foo) also works.
It depends. Sometimes you have a function that takes two arguments from unrelated namespaces (e.g. in I/O or serialization), it could reside in either of those (but not in the global namespace!)
// foo can be either in N1 or N2, but not in global
namespace N1 { auto foo(A&, N2::B const&) }
namespace N2 { auto foo(N1::A&, B const&) }
Or you have an algorithm that is supposed to work for generic arguments (e.g. input and output ranges) you would put that function in its own namespace
// algo should probably be in its own namespace N
namespace N {
template<class R1, class R2>
auto algo(R1 const& in, R2& out)
}
Calling such an algorithm is best done without relying on ADL, i.e. as N::algo(rin, rout).

Why can't I overload a non-class function with a class function?

I have two overloaded functions 'func'. func(int,int) is defined outside class and func(int) is defined inside. How can I call func(int,int) from inside the class's member functions?
#include <iostream>
using namespace std;
int func(int a, int b)
{ return a+b;}
class test
{
int a;
public:
int func(int);
int driver();
};
int test::func(int b)
{ return b;}
int test::driver()
{ return func(10,20);}
int main()
{
test A;
cout<<A.driver(); //ERROR: NO MATCHING FUNCTION TO CALL FUNC(INT,INT)
return 0;
}
return ::func(10,20);
Using :: in front of a name means to look in the global namespace. It will then find the global func, not the func contained in the class.
EDIT:
func in the class isn't overloading the global func per se, but is hiding it. When lookup starts for func when it is called, it finds test::func first, even though ::func is a better match. Changing the name or removing test::func will remove the first match that lookup came across, and it will proceed until it finds the next one, ::func.
As to why it doesn't start in the global namespace, there are many reasons. I can't speak for the people who designed it, but these are all problems that would occur if it were changed.
1: Anybody writing code in a namespace would have to qualify every name with the namespace (std::cout vs cout). Failure to do so could lead to silent bugs where the wrong variables were changed, depending on what existed in the scopes above it.
2: Unqualified lookup would find functions less likely to be related to the code sooner (the function right next to where you called it is far more likely to be related to your code than the one in a different header file two namespaces above you).
3: Functions would have the opposite lookup of variables. I can't specify the scope of a local inside a function (void func() { int i; /*no*/func::i = 0;/*no*/}), so lookup for variables would still have to start in the enclosing scope and work outwards. It would make no sense for the two to work in opposite directions.

gcc template resolution and namespaces

Warning, C++ hating ahead...
I have seen here slightly different variations of this issue, here is my take
namespace space {
}
template <typename T> struct C
{
void foo() {
using namespace space;
bar(t);
}
T t;
};
class A {
};
namespace space {
void bar(const A& a){
}
}
int main()
{
C<A> c;
c.foo();
return 0;
}
if bar is not inside a namespace, everything compiles ok. Putting a namespace breaks compilation with gcc. What is more interesting - gcc finds the function, but just don't feel like using it:
ConsoleApplication1.cpp: In instantiation of 'void C<T>::foo() [with T = A]':
ConsoleApplication1.cpp:26:10: required from here
ConsoleApplication1.cpp:8:8: error: 'bar' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point
instantiation [-fpermissive]
bar(t);
^
ConsoleApplication1.cpp:18:6: note: 'void space::bar(const A&)' declared here, later in the translation unit
void bar(const A& a){
Is there any sane reason for this behaviour, except that the standard says so? And is there any switch I can make gcc accept this code, since it seems there is no technical issue, and I do not see why such code should not work from a pure language standpoint.
templates are not macros. Name lookup of symbols is done in two contexts: first, where you wrote the template, and second pass of only argument-dependent lookup (ADL, or Koeing Lookup) when you pass the template a type (when the template "factory" is instantiated into an actual class or function).
When the function is in the same namespace as A, it is found via ADL. When it is not, it will not be. So when you moved the bar function into space::bar, it was no longer ADL-found with an argument of type A.
This is intentional, to both prevent your template from meaning completely different things at different spots, and to allow non-member interface extensions to types in their own namespace only.
Either use a traits class, stick such helper functions in the same namespace as the type, or pass in functors.
A traits class is probably easiest. Create a class with a static function foo (if you want a default implementation: otherwise leave empty). Call it from your template. Specialize it for A. Now you can implement special behavior for your A type at that point -- it could even call your space::bar function if that function is in view.
Putting bar in the same namespace as A is another solution, and I find it scales better than traits classes. Many of my personal traits classes end up falling back on an ADL lookup, as that lets me inject the handling code right next to where I define A. (The use of traits classes lets me also have my trait handle things in std, where I am not allowed to inject functions for ADL purposes for types living in std (you can inject ADL functions into std, but only for your own types))
The functor solution is how std::map works -- while it falls back on std::less<T> which falls back on operator<, it takes a functor that lets you specify how the key type should be compared within this map.
Is there any sane reason for this behaviour, except that the standard says so?
Sane or not, C++ usually requires names to be declared before use. You don't declare bar before using it; specifically, using namespace space only imports names that have been declared at that point, and not bar.
(If you care about the reason, it's because C++ inherited its declaration rules from the languages of half a century ago, when computers were somewhat primitive. Rules like this allowed compilation in a single pass, so that the compiler didn't have to keep waiting for the operator to put the stack of punch cards back into the hopper. Or something like that; I'm not quite sure how computers worked back then.)
And is there any switch I can make gcc accept this code
As the error message says, -fpermissive. But your code won't be portable if you don't stick to the standard.
This error has nothing to do with namespaces or templates at all, but is the standard error of using a function before it has been declared. Just as you cannot do:
void caller() { callee(); }
void callee() {}
But must instead do:
void callee() {}
void caller() { callee(); }
Or:
void callee();
void caller() { callee(); }
void callee() {}
... the same applies for more complicated functions involving templates and namespaces. Note that if you reorder slightly, it works just fine:
class A {
};
namespace space {
void bar(const A& a){
}
}
template <typename T> struct C
{
void foo() {
using namespace space;
bar(t);
}
T t;
};
int main()
{
C<A> c;
c.foo();
return 0;
}