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.
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.
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
}
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.
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).
Consider the following C++ code example:
namespace n
{
struct A {};
}
struct B {};
void foo(int) {}
template<typename T>
void quux()
{
foo(T());
}
void foo(n::A) {}
void foo(B) {}
int main()
{
quux<n::A>(); // Error (but works if you comment out the foo(int) declaration)
quux<B>(); // Works
return 0;
}
As indicated in the comment, the template instantiation quux<n::A>() causes a compiler error (on GCC 4.6.3):
foo.cpp: In function ‘void quux() [with T = n::A]’:
foo.cpp:22:16: instantiated from here
foo.cpp:13:5: error: cannot convert ‘n::A’ to ‘int’ for argument ‘1’ to ‘void foo(int)’
Can someone explain to me what is going on? I would have expected for it to work the same as with quux<B>(). It must have something to do with when foo is considered dependent. Unfortunately my C++ foo is not good enough. The example compiles fine, when the foo(int) declaration is not present, which is also surprising to me.
Any hints, explanations and workarounds are welcome.
Update 1:
I do not want to (read cannot) move the declaration of foo(n::A) before the definition of quux (which would avoid the error).
Update 2:
Thanks for David for pointing out the related question Template function call confused by function with wrong signature declared before template. The accepted answer by Johannes Schaub - litb proposes a wrapper class solution, that would also work in my case as a workaround. However, I'm not 100% happy with it.
Update 3:
I solved the issue by putting the definition of foo(n::A) in namespace n. Thanks for the helpful answers of Jesse Good and bames53 that not only point out the relevant sections of the standard, but also provide alternative solutions. Thanks to David Rodríguez - dribeas for his explanation when I did not understand the proposed solutions properly and all other contributors.
I think the rule is 14.6.4.2p1:
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.
— For the part of the lookup using associated namespaces (3.4.2), only
function declarations found in either the template definition context
or the template instantiation context are found.
void foo(n::A) {} is not visible in the template definition context because it comes after and foo is not in the same namespace as n::A. So it needs to be either visible before the template definition or included in the same namespace like below:
namespace n
{
void foo(n::A) {}
}
The error my compiler gives is:
main.cpp:11:5: error: call to function 'foo' that is neither visible in the template definition nor found by argument-dependent lookup
foo(T());
^
main.cpp:18:5: note: in instantiation of function template specialization 'quux<n::A>' requested here
quux<n::A>(); // Error (but works if you comment out the foo(int) declaration)
^
main.cpp:14:6: note: 'foo' should be declared prior to the call site or in namespace 'n'
void foo(n::A) {}
^
Which makes it clear what the problem is.
Commenting out void foo(int) does not make it work however; that's just a bug/extension in your compiler.
You mention that you can't define void foo(n::A) before quux(), however when you say in the comments that you can't define it inside namespace n, the reasons you give don't seem to apply. This should fix the problem without the other problems you mention.
template<typename T>
void quux()
{
foo(T());
}
namespace n {
void foo(n::A) {}
}
using n::foo; // in case there's any other code that depends on getting foo(n::A) from the global namespace
void foo(B) {} // this stays in the global namespace
If you can't move the definition of void foo(n::A) to where it works with proper two-phase lookup (again, either before quux() or inside namespace n) there's a sort of hacky solution which may work for you: forward declare the proper overload of foo() inside quux().
template<typename T>
void quux()
{
void foo(T);
foo(T());
}
The function eventually must be defined inside the same namespace as quux() and it has to match the 'generic' forward declaration.
Or there's another alternative. It's only been fairly recent that most C++ compilers started offering correct two-phase name lookup, so there's a lot of code out there that isn't correct but which compilers want to support. If you can't change your code then it may be a good candidate for enabling a compatibility compiler option; my compiler takes the flag -fdelayed-template-parsing to disable two-phase name lookup and instead always look names up in the instantiation context.