Why does gcc hide overloaded functions in the global namespace? - c++

void f() {}
namespace test
{
void f(int) {}
void g() { f(); } // error in gcc 6.2.0
}
int main()
{
test::g();
}
Compile it with g++ -std=c++1z main.cpp, the output is as follows:
main.cpp: In function 'void test::g()':
main.cpp:9:4: error: too few arguments to function 'void test::f(int)'
f(); // error in gcc
^
main.cpp:5:6: note: declared here
void f(int) {}
My compiler is gcc 6.2.0.
Why does gcc hide overloaded functions in the global namespace? Is this conforming to the C++ standard?

Why does gcc hide overloaded functions in the global namespace? Is this conforming to the C++ standards?
Yes. In short, you can't overload functions through different scopes. According to the rule of unqualified name lookup, for the invoking of f() in g(), the name f could be found inside the namespace test, then the name lookup stops; overload resolution takes place after that (based on the names found). That means f() in global namespace won't be considered at all even it looks more appropriate here.
(emphasis mine)
For an unqualified name, that is a name that does not appear to the
right of a scope resolution operator ::, name lookup examines the
scopes as described below, until it finds at least one declaration
of any kind, at which time the lookup stops and no further scopes are
examined.
In order to compile a function call, the compiler must first perform
name lookup, which, for functions, may involve argument-dependent
lookup, and for function templates may be followed by template
argument deduction. If these steps produce more than one candidate
function, then overload resolution is performed to select the function
that will actually be called.
You can use using to introduce the names into the same scope, i.e. to make them actual overloaded functions.
namespace test
{
using ::f; // introduce the name from global namespace
void f(int) {}
void g() { f(); } // fine
}

Related

Dependent name lookup in function template: clang rejects, gcc accepts

Consider the following fragment:
struct X { };
namespace foo {
template <class T>
void bar() { T{} < T{}; }
void operator<(const X&, const X&) {}
}
int main() {
foo::bar<X>();
}
clang rejects this code, gcc accepts it. Is this a gcc bug or is this a clang bug?
I believe this is a gcc bug, filed as 70099. From [temp.dep.res]:
In resolving dependent names, names from the following sources are considered:
(1.1) — Declarations that are visible at the point of definition of the template.
(1.2) — Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.
foo::operator<() isn't visible at the point of definition of the template, and isn't in an associated namespace from the function arguments (X's associated namespace is just the global namespace ::). So I think gcc is wrong to find foo::operator< and clang is correct to reject the code.
GCC is wrong Clang is correct. The fact that GCC swallows invalid code as the one that you showed is also mentioned in CLANG's compatibility page here.
Unqualified names are looked up in the following ways.
The compiler conducts unqualified lookup in the scope where the name was written. For a template, this means the lookup is done at the point where the template is defined, not where it's instantiated. Since operator< hasn't been declared yet at this point, unqualified lookup won't find it.
If the name is called like a function, then the compiler also does argument-dependent lookup (ADL). (Sometimes unqualified lookup can suppress ADL; see [basic.lookup.argdep] paragraph 3 for more information.) In ADL, the compiler looks at the types of all the arguments to the call. When it finds a class type, it looks up the name in that class's namespace; the result is all the declarations it finds in those namespaces, plus the declarations from unqualified lookup. However, the compiler doesn't do ADL until it knows all the argument types.

Default function parameter value visible in template but it shouldn't (gcc)

Consider the code below:
#include <utility>
void f(int, int);
void g(int, int);
struct functor
{
template<typename... T>
void operator()(T&&... params)
{
return f(std::forward<T>(params)...);
}
};
int main()
{
functor()(1); // can use the default value here, why?!
// g(1); // error here as expected, too few arguments
}
void f(int a, int b = 42) {}
void g(int a, int b = 24) {}
This is a thin wrapper around a function call. However, inside functor::operator(), f doesn't have its default value for the second parameter known (it is visible only after main, in the definition), so the code should not compile. g++5.2 compiles it successfully though, but clang++ spits out the expected message that one expects for compilers that perform the two-phase name lookup correctly:
error: call to function 'f' that is neither visible in the
template definition nor found by argument-dependent lookup
return f(std::forward(params)...);
Is this a gcc bug or I am missing something here? I.e., is the point of instantiation after the definition of f below main()? But even in this case, it shouldn't work, as at the second phase the function can only be found via ADL, which is not the case here.
[temp.dep.candidate]:
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup ([basic.lookup.unqual]), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations found in either the template definition context or the template instantiation context are found.
If the call would be ill-formed or would find a better match had the lookup within the associated namespaces
considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation
contexts, then the program has undefined behavior.
Note that ADL is not even working here, as the involved types are fundamental (their set of associated namespaces is empty).

What is C++ name lookup doing here? (& is GCC right?)

I was having a problem in some production code that I minimized to the following test case:
template<typename T>
void intermediate(T t)
{
func(t); // line 4 ("func not declared in this scope")
}
namespace ns {
struct type {};
}
void func(ns::type const & p); // line 11 ("declared here, later")
void foo(ns::type exit_node)
{
intermediate(exit_node); // line 15 ("required from here")
}
GCC 4.5 compiles this fine. Both with and without -std=c++11, 4.7 and 4.9 produce messages like:
test.cpp: In instantiation of ‘void intermediate(T) [with T = ns::type]’:
test.cpp:15:27: required from here
test.cpp:4:5: error: ‘func’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
test.cpp:11:6: note: ‘void func(const ns::type&)’ declared here, later in the translation unit
All of the following three things will cause the file to successfully compile:
Move func(ns::type) into the ns namespace (allowing ADL to find it in ns)
Move type into the global namespace (allowing ADL to find it in ::)
Get rid of intermediate and call func directly from foo
So... what is going on here? Is it legal for GCC to reject this program? Why is func found by unqualified lookup in the third variant (call func directly from foo) but not found by unqualified lookup in the original variant at the point of instantiation?
The general rule is that anything that is not in the template definition context can only be picked up via ADL. In other words, normal unqualified lookup is performed only in the template definition context.
Since no declaration of func is visible when intermediate was defined, and func is not in a namespace associated with ns::type, the code is ill-formed.
GCC is right. func can only be found via ADL since it is an unqualified, dependent function call. func is declared in the global namespace but that is not an associated namespace of ns::type, only ns is (which is why your current code fails). When you replace intermediate(exit_node) with a direct call to func(exit_node) inside foo, then it is found by normal unqualified lookup.

Interesting behavior of compiler with namespaces

Assume the following code:
#include <iostream>
using namespace std;
namespace X
{
class A{};
void f(A a){}
void g(int a){}
}
int main()
{
X::A a;
f(a);
g(5);
}
When I compile the code, the following compile error occurs:
main.cpp: In function 'int main()':
main.cpp: error: 'g' was not declared in this scope
So the function f is compiled perfectly, but g isn't. How? Both of them belong to the same namespace. Does the compiler deduce that function f belongs to the X namespace from the argument of type X::A? How does compiler behave in such cases?
X::A a;
f(a);
works because of Argument-Dependent Lookup (Also known as Koenig Lookup). a is an object of class A inside namespace X, when compiler searches a match-able function f, it will look into namespace X in this case. See Argument Dependent Lookup for more information.
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.
When the code f(a), the compiler finds the function void f(A a){} in the namespace X because of the ADL (argument dependent lookup, also known as Koenig lookup).
A is declared in the namespace X, hence when the compiler needs to look up the definition of f, it includes possibilities from that namespace because the object a of type A is in that namespace (as declared X::A a;).
On the other hand, int is not declared in the namespace X, so the namespace X is not included in the lookup. Since no corresponding function for f is found, it fails to compile.

ADL, Ordinary lookup and Dependent function call not working oO

Here is simple code presented which should have worked according to c++ standard I believe :
template<typename T>
void foo(T x)
{
bar(x);
void bar(int);
}
void bar(int) { }
int main()
{
foo(0);
}
Error comes as from GCC 4.7 as:
‘bar’ was not declared in this scope, and no declarations were found
by argument-dependent lookup at the point of instantiation
But in the C++ standard it's written. § 14.6.4.2 :
For a function call that depends on a template parameter, the
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2, 3.4.3) except that:
— For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found.
I may be have got the wrong impression of what's written, can anyone please correct me here?
You should just move the declaration of 'bar' to the top. Because at the point where the template is defined (not instantiated), before 'bar' is invoked, it hasn't be declared.