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.
Related
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.
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.
This is very similar to this question, but I'm not sure the answer there is entirely applicable to the minimal code I've put together that demonstrates the issue. (My code does not use trailing-return types, and there are some other differences as well.) Additionally, the issue of whether MSVC's behavior is legal doesn't seem to be addressed.
In short, I'm seeing the compiler select a generic function template instantiation rather than a more-specific overload when the function template is inside a namespace.
Consider the following set of namespace and class definitions:
namespace DoStuffUtilNamespace
{
template<typename UNKNOWN>
void doStuff(UNKNOWN& foo)
{
static_assert(sizeof(UNKNOWN) == -1, "CANNOT USE DEFAULT INSTANTIATION!");
}
}
class UtilForDoingStuff
{
public:
template <typename UNKNOWN>
void doStuffWithObjectRef(UNKNOWN& ref)
{
DoStuffUtilNamespace::doStuff(ref);
}
};
class MyClassThatCanDoStuff { };
namespace DoStuffUtilNamespace
{
using ::MyClassThatCanDoStuff; // No effect.
void doStuff(MyClassThatCanDoStuff& foo) { /* No assertion! */ }
}
... and the following use-cases:
int main()
{
MyClassThatCanDoStuff foo;
DoStuffUtilNamespace::MyClassThatCanDoStuff scoped_foo;
UtilForDoingStuff util;
DoStuffUtilNamespace::doStuff(foo); // Compiles
DoStuffUtilNamespace::doStuff(scoped_foo); // Compiles
util.doStuffWithObjectRef(foo); // Triggers static assert
util.doStuffWithObjectRef(scoped_foo); // Triggers static assert
}
If the entire DoStuffUtilNamespace is eliminated and all its members are moved to global scope, this compiles fine with G++ and Clang++.
With the namespace, doStuff is of course a dependent name. According to the top-voted answer on the similar question, the standard says:
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 and from the definition context.
This seems a little odd to me; I don't understand why the first bullet point would specify that the declarations must be visible at the point of definition of the template rather than at the point of instantiation, since the second bullet point explicitly specifies that some declarations visible only at the point of instantiation are allowed. (If someone would like to offer a rationale, I'd appreciate it, but that's not my question because it's my understanding that questions of the form "why did the standards committee decide X" are off topic.)
So I think that explains why util.doStuffWithObjectRef(foo); triggers the static assertion: doStuff(MyClassThatCanDoStuff&) hasn't been declared at the point of definition of UtilForDoingStuff::doStuffWithObjectRef<UNKNOWN>(UNKNOWN&). And indeed moving the class UtilForDoingStuff definition after the doStuff overload has been defined seems to fix the issue.
But what exactly does the standard mean by "namespaces associated with the types of the function arguments"? Shouldn't the using ::MyClassThatCanDoStuff declaration, together with the explicit scoping of the scoped_foo instance type within the namespace, trigger argument-dependent lookup, and shouldn't this look-up find the non-asserting definition of doStuff()?
Also, the entire code is compiled without error using clang++ -ftemplate-delayed-parsing, which emulates MSVC's template-parsing behavior. This seems preferable, at least in this particular case, because the ability to add new declarations to a namespace at any time is one of the primary appeals of namespaces. But, as noted above, it doesn't quite seem to follow the letter of the law, according to the standard. Is it permissible, or is it an instance of non-conformance?
EDIT:: As pointed out by KIIV, there is a workaround; the code compiles if template specialization is used instead of overloading. I would still like to know the answers to my questions about the standard.
With the namespace, doStuff is of course a dependent name.
You are starting from the wrong premise. There is no ADL for a qualified call like DoStuffUtilNamespace::doStuff(ref). [basic.lookup.argdep]/p1, emphasis mine:
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.
DoStuffUtilNamespace::doStuff is a qualified-id, not an unqualified-id. ADL doesn't apply.
For this reason, DoStuffUtilNamespace::doStuff is also not a dependent name. [temp.dep]/p1:
In an expression of the form:
postfix-expression ( expression-listopt)
where the postfix-expression is an unqualified-id, the
unqualified-id denotes a dependent name if [...]. If an operand of an operator is a type-dependent expression, the operator also denotes
a dependent name. Such names are unbound and are looked up at the
point of the template instantiation (14.6.4.1) in both the context of
the template definition and the context of the point of instantiation
(The italicization of dependent name indicate that this paragraph is defining the term.)
Instead, per [temp.nondep]/p1:
Non-dependent names used in a template definition are found using the
usual name lookup and bound at the point they are used.
which doesn't find your later overload declaration.
Specialization works because it's still the same function template declaration that's used; you just supplied a different implementation than the default one.
But what exactly does the standard mean by "namespaces associated with
the types of the function arguments"? Shouldn't the using ::MyClassThatCanDoStuff declaration, together
with the explicit scoping of the scoped_foo instance type within the
namespace, trigger argument-dependent lookup
No. using-declarations do not affect ADL. [basic.lookup.argdep]/p2, emphasis mine:
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).
Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of namespaces and classes are
determined in the following way:
If T is a fundamental type, [...]
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
innermost enclosing namespaces of its associated classes. Furthermore,
if T is a class template specialization, its associated namespaces and
classes also include: the namespaces and classes associated with the
types of the template arguments provided for template type parameters
(excluding template template parameters); the namespaces of which any
template template arguments are members; and the classes of which any
member templates used as template template arguments are members. [
Note: Non-type template arguments do not contribute to the set of associated namespaces. —end note ]
[...]
With template specialization I can get it work:
namespace DoStuffUtilNamespace
{
template<typename UNKNOWN>
void doStuff(UNKNOWN& foo)
{
static_assert(sizeof(UNKNOWN) == -1, "CANNOT USE DEFAULT INSTANTIATION!");
}
}
class UtilForDoingStuff
{
public:
template <typename UNKNOWN>
void doStuffWithObjectRef(UNKNOWN& ref)
{
DoStuffUtilNamespace::doStuff(ref);
}
};
class MyClassThatCanDoStuff { };
namespace DoStuffUtilNamespace
{
using ::MyClassThatCanDoStuff;
template <> void doStuff<MyClassThatCanDoStuff>(MyClassThatCanDoStuff& foo) { /* No assertion! */ }
}
int main()
{
MyClassThatCanDoStuff foo;
DoStuffUtilNamespace::MyClassThatCanDoStuff scoped_foo;
UtilForDoingStuff util;
DoStuffUtilNamespace::doStuff(foo); // Compiles
DoStuffUtilNamespace::doStuff(scoped_foo); // Compiles
util.doStuffWithObjectRef(foo); // Compiles
util.doStuffWithObjectRef(scoped_foo); // Compiles
}
Declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context.
Example with the following code which prints B::foo Demo
namespace A
{
template <typename T>
void foo(const T&) {std::cout << "A::foo" << std::endl;}
template <typename T>
void bar(const T& t) {
foo(t); // thank to ADL, it will also look at B::foo for B::S.
}
}
namespace B
{
struct S {};
void foo(const S&) {std::cout << "B::foo" << std::endl;}
}
int main()
{
B::S s;
A::bar(s);
}
So when calling ?::foo(const B::S&), the second bullet point adds B::foo to the list of overloads.
why template-specialization works in this case
There is only one function:
template<>
void DoStuffUtilNamespace::doStuff<MyClassThatCanDoStuff>(MyClassThatCanDoStuff& foo);
even if it is defined later.
Note that the fact that there is a specialization should be known in the translation unit, else the program is ill formed (doesn't respect ODR).
while overloading doesn't.
You think:
So I think that explains why util.doStuffWithObjectRef(foo); triggers the static assertion: doStuff(MyClassThatCanDoStuff&) hasn't been declared at the point of definition of UtilForDoingStuff::doStuffWithObjectRef<UNKNOWN>(UNKNOWN&). And indeed moving the class UtilForDoingStuff definition after the doStuff overload has been defined seems to fix the issue.
Exactly.
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.