ADL, Ordinary lookup and Dependent function call not working oO - c++

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.

Related

Can't understand name lookup differences between an int and a user defined type - perhaps ADL related

Why does the following code compile:
template<typename T>
void foo(T in) { bar(in); }
struct type{};
void bar(type) {}
int main() { foo(type()); }
When the following does not:
template<typename T>
void foo(T in) { bar(in); }
void bar(int) {}
int main() { foo(42); }
Compiling with GnuC++ 7:
a.cpp: In instantiation of 'void foo(T) [with T = int]':
a.cpp:9:20: required from here
a.cpp:2:21: error: 'bar' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
void foo(T in) { bar(in); }
~~~^~~~
a.cpp:8:6: note: 'void bar(int)' declared here, later in the translation unit void bar(int) {}
I would assume that MSVC would compile both (as it does) but that GCC would reject both since GCC/Clang have proper two phase name lookup...
The strange part is not that the int example fails to compile, it is that the type example does since bar is defined after foo. This is due to [temp.dep.candidate] (see third paragraph).
Two-pass compilation of templates
When the compiler parses and compiles a template class or function, it looks up identifiers in two pass:
Template argument independent name lookup: everything that does not depend on the template arguments can be checked. Here, since bar() depends on a template argument, nothing is done. This lookup is done at the point of definition.
Template argument dependent name lookup: everything that could not be looked up in pass #1 is now possible. This lookup is done at the point of instantiation.
You get an error during pass #2.
ADL lookup
When a function name is looked up, it is done within the current context and those of the parameters type. For instance, the following code is valid though f is defined in namespace n:
namespace n { struct type {}; void f(type) {}; }
int main() { n::type t; f(t); } // f is found in ::n because type of t is in ::n
More about ADL (cppreference.com):
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.
Two-pass compilation, ADL lookup and unqualified-id lookup
In your case, those three mechanisms collide. See [temp.dep.candidate]:
For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:
— For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the
template definition context are found.
— For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the
template definition context or the template instantiation context are
found.
So, with foo(type()) unqualified-id lookup kicks in and the lookup is done "in either the template definition context or the template instantiation".
With foo(42), 42 being a fundamental type, ADL is not considered and only the "definition context" is considered.
The 1st sample is valid, because ADL takes effect for the name lookup of dependent name in template definition; which makes it possible to find the function bar. (bar(in) depends on the template parameter T.)
(emphasis mine)
For a dependent name used in a template definition, the lookup is postponed until the template arguments are known, at which time ADL examines function declarations that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations that are visible from the template definition context (in other words, adding a new function declaration after template definition does not make it visible except via ADL).
And ADL doesn't work with fundamental types, that's why the 2nd sample fails.

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).

getting an element from a tuple [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why doesn't ADL find function templates?
Calling get does not seem to invoke argument dependent lookup:
auto t = std::make_tuple(false, false, true);
bool a = get<0>(t); // error
bool b = std::get<0>(t); // okay
g++ 4.6.0 says:
error: 'get' was not declared in this scope
Visual Studio 2010 says:
error C2065: 'get': undeclared identifier
Why?
It's because you attempt to explicitly instantiate get function template, by providing 0 as template argument. In case of templates, ADL works if a function template with that name is visible at the point of the call. This visible function template only helps triggering ADL (it may not be used actually) and then, a best matching can be found in other namespaces.
Note that the function template which triggers (or enable) ADL, need not to have definition:
namespace M
{
struct S{};
template<int N, typename T>
void get(T) {}
}
namespace N
{
template<typename T>
void get(T); //no need to provide definition
// as far as enabling ADL is concerned!
}
void f(M::S s)
{
get<0>(s); //doesn't work - name `get` is not visible here
}
void g(M::S s)
{
using N::get; //enable ADL
get<0>(s); //calls M::get
}
In g(), the name N::get triggers ADL when calling get<0>(s).
Demo : http://ideone.com/83WOW
C++ (2003) section §14.8.1/6 reads,
[Note: For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.
[Example:
namespace A {
struct B { };
template<int X> void f(B);
}
namespace C {
template<class T> void f(T t);
}
void g(A::B b) {
f<3>(b); //ill-formed: not a function call
A::f<3>(b); //well-formed
C::f<3>(b); //ill-formed; argument dependent lookup
// applies only to unqualified names
using C::f;
f<3>(b); //well-formed because C::f is visible; then
// A::f is found by argument dependent lookup
}
—end example] —end note]
ADL doesn't directly apply to template-id's such as get<0>, so the compiler doesn't really get started down that path. C++11 §14.8.1/8 (in C++03, 14.8.1/6):
[ Note: For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.
It goes on to give a short example. So the workaround is quite easy:
#include <tuple>
template< typename > // BEGIN STUPID BUT HARMLESS HACK
void get( struct not_used_for_anything ); // END STUPIDITY
auto t = std::make_tuple(false, false, true);
bool a = get<0>(t); // Now the compiler knows to use ADL!
bool b = std::get<0>(t); // okay
http://ideone.com/fb8Ai
Note that the not_used_for_anything in the above is merely a safety mechanism. It's intended to be an incomplete type which is never completed. Omitting it works as well, but is unsafe because it could collide with a signature you might want.
template< typename >
void get() = delete;
http://ideone.com/WwF2y
Note: the above quote from the Standard is non-normative, meaning that in the opinion of the Committee, we would be able to figure this out without explanation, because it's implied by the rest of the language and grammar, particularly the fact that 3.4.2 says nothing about looking up template-ids. Yeah, right!

Two-phase function template compilation: not *only* ADL is employed in the 2nd phase?

I'm wondering why the following code compiles.
#include <iostream>
template<class T>
void print(T t) {
std::cout << t;
}
namespace ns {
struct A {};
}
std::ostream& operator<<(std::ostream& out, ns::A) {
return out << "hi!";
}
int main() {
print(ns::A{});
}
I was under impression that at the instantiation point unqualified dependent names are looked-up via ADL only - which should not consider the global namespace. Am I wrong?
This is an interesting case. The workings of name lookup as you describe them is summarized here:
[temp.dep.candidate] (emphasis mine)
1 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, 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.
The bit I highlighted is the crux of the matter. The description for "ADL only" is for function calls of the from foo(bar)! It does not mention calls that result from an overloaded operator. We know that calling overloaded operators is equivalent to calling a function, but the paragraph speaks of expressions in a specific form, that of a function call only.
If one was to change your function template into
template<class T>
void print(T t) {
return operator<< (std::cout, t);
}
where now a function is called via postfix-expression notation, then wo and behold: GCC emits an equivalent error to Clang. It implements the above paragraph reliably, just not when it comes to overloaded operator calls.
So is it a bug? I would say it is. The intent is surely that overloaded operators be found like named functions (even when called from their respective expression form). So GCC needs to be fixed. But the standard could use a minor clarification of the wording too.