The below code is part of a cpp quiz that I was going through :
#include <iostream>
template<typename T>
void foo(T)
{
std::cout << "T" << std::endl;;
}
struct S
{
};
template<typename T>
void call_foo(T t)
{
foo(S());
foo(t);
}
void foo(S)
{
std::cout << "S" << std::endl;
}
int main()
{
call_foo(S());
}
I fail to understand why the output turns out to be TS. I expected it to be SS
Compiler : gcc version 4.8.5 20150623
§14.6¶9 states: "When looking for the declaration of a name used in a
template definition, the usual lookup rules (§3.4.1, §3.4.2) are used
for non-dependent names. The lookup of names dependent on the template
parameters is postponed until the actual template argument is known
(§14.6.2)."
The first call to foo is a non-dependent call, so it is looked up at the time of definition of the function template. In case of the second call, it is deferred until the template is instantiated because it depends on a template parameter.
template<typename T> void call_foo_function(T t)
{
foo(S()); // Independent, looks up foo now.
foo(t); // Dependent, looks up foo later.
}
When foo is being looked up at the time of definition of the function template, the only version of foo that exists is the templated foo(T). Specifically, foo(S) does not exist yet, and is not a candidate.
Interesting thing would be check what your code outputs in Visual Studio, I think in that case it would output the SS that you expected.
Source of the answer : CPPQuiz.
Unfortunately, I do not have the exact link of the answer anymore since I am not able to find it again.
You were expecting the two calls to be resolved identically, via argument dependent lookup. But in this case:
foo(S());
foo(t);
The first foo is not a dependent name. Recall that name lookup for functions in templates is done in two ways:
Regular unqualified name lookup for all the overloads at the point of the function template's definition.
For dependent names, argument dependent lookup is done at both the point of template definition and instantiation.
Since, again, the first call is not dependent, only regular unqualified name lookup is done. At that point, the only visible overload is the function template foo you defined previously. The second overload is not yet available, hence it's not called.
Related
template <typename T>
int get_num(const T&)
{
return 42;
}
struct Foo
{
int i = get_num(*this);
};
int get_num(const Foo&)
{
return 23;
}
int main()
{
std::cout << Foo().i << std::endl; // MinGW64 - 42, MSVC - 23
return 0;
}
MSVC chooses non-template get_num "overload". It will successfully link even if the template is only forward-declared.
MinGW64 will choose the default template implementation. Will fail to link if there is no definition for the template.
Who is right and who is wrong? Whad does the standard say?
However this version yields the same results for both compilers... Why does it not go to infinite recursion?
template <typename T>
int get_num(const T& t)
{
std::cout << "Template version called" << std::endl;
return get_num(t);
}
struct Foo
{
int i = get_num(*this);
};
int get_num(const Foo&)
{
std::cout << "Non-Template version called" << std::endl;
return 23;
}
MSVC output:
Non-Template version called
23
MinGW64 Output:
Template version called
Non-Template version called
23
I think ADL is involved when using MSVC.
For the first sample, MinGW is correct and MSVC is incorrect: the get_num call can only consider the function template.
This is a question of overload resolution, so I'll start in clause [over]. get_num(*this) is a plain function call expression, so [over.call.func] applies:
In unqualified function calls, the name is not qualified by an -> or . operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls. The function declarations found by that lookup constitute the set of candidate functions.
"Name lookup" is discussed in section [basic.lookup]. Paragraph 2:
A name "looked up in the context of an expression" is looked up as an unqualified name in the scope where the expression is found.
One complication here is that the get_num(*this) default member initializer expression doesn't get used by anything until the default constructor of Foo is implicitly defined by its odr-use in main. But the lookup is determined from the code location of the expression itself, no matter that it's used in the process of that implicit definition.
For the second code sample, MinGW is again correct: the apparently recursive call inside the template definition actually calls the non-template function.
This is a result of "two phase lookup" for dependent function calls, described in section [temp.dep.res]. Briefly, since the type of t depends on a template parameter, the name get_num in the expression get_num(t) is considered a dependent name. So for each instantiation of the function template, it gets two ways of finding candidates for overload resolution: the ordinary immediate way which finds the get_num function template, plus another lookup from the point of instantiation. The specialization get_num<Foo> has point of instantiation right after the main() definition, so overload resolution is able to find the non-template from the instantiation context, and the non-template wins overload resolution.
(Argument-dependent lookup is a related tangent issue to this second point. ADL applies to declarations from the instantiation context but not declarations from the definition context. But it's not directly a reason for the behaviors in either example program.)
None of this has changed significantly between C++14 and the latest draft, as far as I can see.
Consider this piece of code.
Try to guess the output of the program before reading further:
#include <iostream>
using namespace std;
template <typename T>
void adl(T) {
cout << "T";
}
struct S {
};
template <typename T>
void call_adl(T t) {
adl(S());
adl(t);
}
void adl(S) {
cout << "S";
}
int main() {
call_adl(S());
}
Are you done? OK.
So the output of this program is TS, which looks counterintuitive (at least for me).
Why is the call adl(S()) inside call_adl using the template overload instead of the one that takes S?
The behaviors of name lookup are different for dependent name and non-dependent name in templates.
For a non-dependent name used in a template definition, unqualified name lookup takes place when the template definition is examined. The binding to the declarations made at that point is not affected by declarations visible at the point of instantiation. 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 with external linkage (until C++11) that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations with external linkage (until C++11) 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).
That means for adl(S());, adl(S) declared after call_adl is not visible, then the templated adl(T) is selected. For adl(t);, t is a dependent name (depending on the template parameter T), the lookup is postponed and adl(S) is found by ADL and it wins against adl(T) in overload resolution.
This program works as expected:
#include <iostream>
template <typename T>
void output(T t) {
prt(t);
}
struct It {
It(int* p) : p(p) {}
int* p;
};
void prt(It it) {
std::cout << *(it.p) << std::endl;
}
int main() {
int val = 12;
It it(&val);
output(it);
return 0;
}
When you compile and execute this, it prints "12" as it should. Even though the function prt, required by the output template function, is defined after output, prt is visible at the point of instantiation, and therefore everything works.
The program below is very similar to the program above, but it fails to compile:
#include <iostream>
template <typename T>
void output(T t) {
prt(t);
}
void prt(int* p) {
std::cout << (*p) << std::endl;
}
int main() {
int val = 12;
output(&val);
return 0;
}
This code is trying to do the same thing as the previous example, but this fails in gcc 8.2 with the error message:
'prt' was not declared in this scope, and no declarations were found by
argument-dependent lookup at the point of instantiation [-fpermissive]
The only thing that changed is that the argument passed to output is a built-in type, rather than a user-defined type. But I didn't think that should matter for name resolution. So my question is: 1) why does the second example fail?; and 2) why does one example fail and the other succeeds?
The Standard rule that applies here is found in [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, 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.
In both examples, unqualified name lookup finds no declarations of prt, since there were no such declarations before the point where the template was defined. So we move on to argument-dependent lookup, which looks only in the associated namespaces of the argument types.
Class It is a member of the global namespace, so the global namespace is the one associated namespace, and the one declaration is visible within that namespace in the template instantiation context.
A pointer type U* has the same associated namespaces as type U, and a fundamental type has no associated namespaces at all. So since the only argument type int* is a pointer to fundamental type, there are no associated namespaces, and argument-dependent lookup can't possibly find any declarations in the second program.
I can't exactly say why the rules were designed this way, but I would guess the intent is that a template should either use the specific declared functions it meant to use, or else use a function as an extensible customization point, but those user customizations need to be closely related to a user-defined type they will work with. Otherwise, it becomes possible to change the behavior of a template that really meant to use one specific function or function template declaration by providing a better overload for some particular case. Admittedly, this is more from the viewpoint of when there is at least one declaration in the template definition context, not when that lookup finds nothing at all, but then we get into cases where SFINAE was counting on not finding something, etc.
Here is two-phase name lookup for template from iso-standard:
When looking for the declaration of a name used in a template definition, the usual lookup rules (6.4.1, 6.4.2) are used for non-dependent names.
The lookup of names dependent on the template parameters is postponed until the actual template argument is known
Sample codes:
#include <iostream>
void WithoutTemplate(int) {std::cout << "NonTemplate: int\n";}
template<typename T>
void WithTemplate(T) {std::cout << "no match\n";}
template<>
void WithTemplate(int) {std::cout <<"Template: int\n";}
template<typename T>
void test(T)
{
WithTemplate(1.1);
WithoutTemplate(1.1);
}
void WithoutTemplate(double) {std::cout << "nontemplate: double\n";}
template<>
void WithTemplate(double) {std::cout << "template: double\n";}
int main()
{
test(1.1);
}
output:
template: double
NonTemplate: int
There are two functions: WithTemplate and WithoutTemplate. The parameter 1.1 is non-dependent(though it is prvalue, which has no name? I assume it still obey non-dependent name's rules)
name lookup of WithoutTemplate meets 2-phase lookup, because when calling WithoutTemplate(1.1), void WithoutTemplate(double) is not visible. So the output NonTemplate: int is easy to understand.
However, the case which invokes full specialization function quite confuses me. its behaviour is opposite to the standard's rules(2-phase lookup). I thought it should output template: int
So, is there other name lookup rules for specialization? Or something else I misunderstand?
Here is what I have read:
Difference between instantiation and specialization in c++ templates
Name lookups in C++ templates
Your program has undefined behaviour, because you define the explicit specialization of WithTemplate<double> after it has been implicitly instantiated through the call WithTemplate(1.1). Explicit specializations must appear before any use of them that would cause instantiation - see e.g. http://en.cppreference.com/w/cpp/language/template_specialization.
So there's no point trying to reconcile the behaviour with what the standard says; the standard explicitly says nothing about what should happen here.
Consider the following code:
#include <iostream>
template<typename T>
void f(T t)
{
(void)t;
std::cout << "templated f(T)\n";
}
template<typename T>
void entry(T t)
{
f(t);
}
void f(double d)
{
(void)d;
std::cout << "normal f(double)\n";
}
int main()
{
double d = 0.0;
entry(d);
return 0;
}
Output:
templated f(T)
I find this surprising, because I thought that the plain function will be selected over any templated version. Why does this happen?
Another thing I noticed while playing around is that: if I put the normal function void f(double) before the templated void entry(T) function the code will call the normal function, basically outputting:
normal f(double)
Therefore my other question: why does the order matter in this particular example?
f is a dependent name, since it depends on t whose type is a template parameter. The name lookup rules for dependent names are given in [temp.dep.res]/1:
In resolving dependent names, names from the following sources are considered:
Declarations that are visible at the point of definition of the template.
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.
In other words, normally name lookup inside a template only finds names that have been declared before the template definition (which is not that surprising, since it's the same as for non-templates). The second bullet point allows names declared after the template definition to be found, but only when ADL occurs. This won't be the case when the argument is a fundamental type such as double.
The overload for f(double) is not visible to the compiler when the entry(T) template is parsed. Therefore, it won't participate in overload resolution when the entry(T) template is instantiated. This is just an obscure rule when it comes to resolving overloads in a template instantiation context. In order for an overload to be considered, it has to already have been visible in the translation unit before the template definition was parsed.