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); }
};
Related
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.
Consider following code snippet:
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
foo(Bar::A);
}
};
It fails to compile, the message from gcc 9.2 is:
:12:19: error: no matching function for call to 'Baz::foo(Bar)'
12 | foo(Bar::A);
|
I don't suspect it is a bug since clang 10 also fails. I have two questions regarding this situation:
Where does standard define bahaviour for such overloads?
What are the possible reasons that compiler behaviour is specified that way?
live example
The call to foo inside Baz::foo() will only look up names inside the class. If you mean to use the foo declared outside the class Baz, you need to use the scope-resolution operator, like this:
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
::foo(Bar::A); // looks up global 'foo'
}
};
Note that the unscoped call to foo fails because there is a Bar::foo that is found in the closest scope. If you name the function differently, then no function is found in Bar, and the compiler will look in the outer scope for the function.
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void goo() { // not 'foo'
foo(Bar::A); // this is fine, since there is no 'Bar::foo' to find
}
};
Here's the quote from cppreference for a class definition.
e) if this class is a member of a namespace, or is nested in a class that is a member of a namespace, or is a local class in a function that is a member of a namespace, the scope of the namespace is searched until the definition of the class, enclosing class, or function. if the lookup of for a name introduced by a friend declaration: in this case only the innermost enclosing namespace is considered, otherwise lookup continues to enclosing namespaces until the global scope as usual.
Of course, this only applies to class definitions, but for member functions (which is your example), it says
For a name used inside a member function body, a default argument of a member function, exception specification of a member function, or a default member initializer, the scopes searched are the same as in [class definition], ...
So the same logic applies.
According to the rule of unqualified name lookup, from the standard, [basic.lookup.unqual]/1,
(emphasis mine)
In all the cases listed in [basic.lookup.unqual], 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.
That means the name foo is found at the class scope (i.e. the Baz::foo itself), then name lookup stops; the global one won't be found and considered for the overload resolution which happens later.
About your 2nd question, functions can't be overloaded through different scopes; which might cause unnecessary confusion and complexity. Consider the following code:
struct Baz {
void foo(int i) { }
void foo() {
foo('A');
}
};
You know 'A' would be converted to int then passed to foo(int), that's fine. If functions are allowed to be overloaded through scopes, if someday a foo(char) is added in global scope by someone or library, behavior of the code would change, that's quite confusing especially when you don't know about the adding of the global one.
In this example why do I need to qualify the function call B::F() with its namespace? As the typedef of QF should match the type Q as I thought it was an alias for it, not really a new type?
Is there an elegant way around this that doesn't require a using statement in every function body?
namespace A
{
template<class T> struct V {};
template<class T> struct Q {};
typedef Q<float> QF;
template<class T>
inline void F(V<T> v) {}
namespace B
{
template<class T>
inline void F(Q<T> q) {}
}
namespace C
{
void Test();
}
}
using namespace A;
using namespace A::B;
void A::C::Test()
{
QF q;
// using namespace A::B; // Uncomment will work
F(q); // Error, tries A::F() and can't find B::F()
B::F(q); // Ok it uses B::F() as intended
}
int main()
{
return 0;
}
I'll try to show in what ways clang interprets the draft differently than gcc and msvc. When you call F(q) inside the definition of void A::C::Test(), the compiler tries to look up the name F in the scopes in which that call is made, and will stop looking for larger scopes as soon as that name (name, not particular overload) is found. The body of void A::C::Test() is inside the namespace C which is inside A which is inside the global namespace. So when you write the using directive in the global scope, the relevant passage in the standard [basic.lookup.unqual]:
In all the cases listed in [basic.lookup.unqual], 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.
The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see
[namespace.udir]. For the purpose of the unqualified name lookup rules
described in [basic.lookup.unqual], the declarations from the
namespace nominated by the using-directive are considered members of
that enclosing namespace.
by point 2 implies that the name F (coming from A::B::F) is visible as if it was declared in the global scope, but by point 1 name lookup will find a name F sooner, in namespace A and will not look further. So it only finds void F(V<T> v) and this declaration is not fit for the call.
The more interesting story is with the using directive put inside the body of the function. The difference in approach is whether the definition of void A::C::Test() (which is also a declaration) appears in the global namespace or in namespace A::C. If you take the view that this is the global namespace (as clang apparently does), then the namespace enclosing the using-directive written inside the function is the global namespace and we are back to the explanation above. But if you believe that it appears in namespace A::C, then you bring in (among others) the declaration of void F(Q<T>) into A::C and regular lookup finds it.
A bonus observation is why you would still be able to call F(V<double>{}) since now the declaration void F(Q<T>) is in a narrower scope - and the answer is argument-dependent lookup, the namespace where V<T> is declared is going to be looked at too.
That's a story to scare the learner, but if you want practical guidance, do not use the shortcut with namespaces, use
namespace A::C
{
void Test()
{
...
}
}
so that the namespace in which it is declared is not subject to debate and put using namespace A::B; either in namespace scope or in function scope.
(And I'll try to figure out what was the real intended scope of the void A::C::Test() declaration-definition with wiser people).
In C++, what is the purpose of the scope resolution operator when used without a scope? For instance:
::foo();
It means global scope. You might need to use this operator when you have conflicting functions or variables in the same scope and you need to use a global one. You might have something like:
void bar(); // this is a global function
class foo {
void some_func() { ::bar(); } // this function is calling the global bar() and not the class version
void bar(); // this is a class member
};
If you need to call the global bar() function from within a class member function, you should use ::bar() to get to the global version of the function.
A name that begins with the scope resolution operator (::) is looked up in the global namespace. We can see this by looking at the draft C++ standard section 3.4.3 Qualified name lookup paragraph 4 which says (emphasis mine):
A name prefixed by the unary scope operator :: (5.1) is looked up in global scope, in the translation unit where it is used. The name shall be declared in global namespace scope or shall be a name whose declaration is visible in global scope because of a using-directive (3.4.3.2). The use of :: allows a global name to be referred to even if its identifier has been hidden (3.3.10).
As the standard states this allows us to use names from the global namespace that would otherwise be hidden, the example from the linked document is as follows:
int count = 0;
int main(void) {
int count = 0;
::count = 1; // set global count to 1
count = 2; // set local count to 2
return 0;
}
The wording is very similar going back to N1804 which is the earliest draft standard available.
Also you should note, that name resolution happens before overload resolution. So if there is something with the same name in your current scope then it will stop looking for other names and try to use them.
void bar() {};
class foo {
void bar(int) {};
void foobar() { bar(); } // won't compile needs ::bar()
void foobar(int i) { bar(i); } // ok
}
When you already have a function named foo() in your local scope but you need to access the one in the global scope.
My c++ is rusty but I believe if you have a function declared in the local scope, such as foo() and one at global scope, foo() refers to the local one. ::foo() will refer to the global one.
referring to the global scope
In C++, what is the purpose of the scope resolution operator when used without a scope? For instance:
::foo();
It means global scope. You might need to use this operator when you have conflicting functions or variables in the same scope and you need to use a global one. You might have something like:
void bar(); // this is a global function
class foo {
void some_func() { ::bar(); } // this function is calling the global bar() and not the class version
void bar(); // this is a class member
};
If you need to call the global bar() function from within a class member function, you should use ::bar() to get to the global version of the function.
A name that begins with the scope resolution operator (::) is looked up in the global namespace. We can see this by looking at the draft C++ standard section 3.4.3 Qualified name lookup paragraph 4 which says (emphasis mine):
A name prefixed by the unary scope operator :: (5.1) is looked up in global scope, in the translation unit where it is used. The name shall be declared in global namespace scope or shall be a name whose declaration is visible in global scope because of a using-directive (3.4.3.2). The use of :: allows a global name to be referred to even if its identifier has been hidden (3.3.10).
As the standard states this allows us to use names from the global namespace that would otherwise be hidden, the example from the linked document is as follows:
int count = 0;
int main(void) {
int count = 0;
::count = 1; // set global count to 1
count = 2; // set local count to 2
return 0;
}
The wording is very similar going back to N1804 which is the earliest draft standard available.
Also you should note, that name resolution happens before overload resolution. So if there is something with the same name in your current scope then it will stop looking for other names and try to use them.
void bar() {};
class foo {
void bar(int) {};
void foobar() { bar(); } // won't compile needs ::bar()
void foobar(int i) { bar(i); } // ok
}
When you already have a function named foo() in your local scope but you need to access the one in the global scope.
My c++ is rusty but I believe if you have a function declared in the local scope, such as foo() and one at global scope, foo() refers to the local one. ::foo() will refer to the global one.
referring to the global scope