I don't understand why it isn't correct
#include <iostream>
using namespace std;
struct CL{};
template <typename T>
void fnc(T t)
{
f(t);
}
namespace NS {
void f(CL){}
void fn() {fnc(CL()); /*error is here*/}
//point of instantiation fnc<CL> is here (in namespace scope,
//according to 14.6.4.1/1)
}
int main(){}
Calling f(t)
in template function fnc
is dependent on template parameter and then name lookup must be at an instantiation point. I saw Standard (C++ 14) 14.6.4.1/1
For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
f(CL)
is visible at a point of instantiation of fnc<CL>
, but all the compilers (VS, gcc, clang) give an error. What is reason for that behavior?
To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation.
Templates Specialization is defined as a mechanism that allows any programmer to use types as parameters for a class or a function. A function/class defined using the template is called a generic function/class, and the ability to use and create generic functions/classes is one of the critical features of C++.
Function templates are similar to class templates but define a family of functions. With function templates, you can specify a set of functions that are based on the same code but act on different types or classes.
Here the argument t
of fnc
is a dependent name, which cannot be resolved when parsing templates. Instead, they are looked up again at the point of instantiation. This is so-called two-phase lookup: the 1st phase is the parsing of a template, and the 2nd phase is its instantiation.
The answer to your question lies in the fact that the 2nd lookup performed at the POI (point of instantiation) is only an ADL. Because the struct CL
is not defined inside the same namespace with void f(CL)
, the POI lookup would therefore not take place and would not find it.
If you try to put the definition of the struct CL
into the namespace to make ADL take effect, it will compile well.
namespace NS {
struct CL{};
void f(CL){}
//...
}
According to the rule of unqualified name lookup, (bold by me)
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With