Home > OS >  Calling undeclared function template from inside another function template
Calling undeclared function template from inside another function template

Time:02-17

I am learning about templates in C and so trying out different examples. One such example whose output i am unable to understand is given below:

template<typename T> void func(T p) {
g<T>(p); //ERROR
g(p);    //NO ERROR?
}


int main()
{

}

When i try to compile the above code snippet, i get error saying:

prog.cc: In function 'void func(T)':
prog.cc:2:1: error: 'g' was not declared in this scope
    2 | g<T>(p); //ERROR
      | ^
prog.cc:2:4: error: expected primary-expression before '>' token
    2 | g<T>(p); //ERROR
      |    ^

My questions are:

  1. Why i am getting this error?
  2. Why i am getting the error only for the statement g<T>(p); and not for g(p);? I thought that writing g(p); is equivalent to g<T>(p); since due to template argument deduction the template parameter for g will be deduced to T.

CodePudding user response:

Case 1

Here we consider the statement: g<T>(p);

template<typename T> void func(T p) {
g<T>(p); //ERROR
}
int main()
{

}

In the above code snippet the name g is a unqualified dependent name. And from source: two phase lookup:

During the first phase, while parsing a template unqualified dependent names are looked up using the ordinary lookup rules. For unqualified dependent names, the initial ordinary lookup—while not complete—is used to decide whether the name is a template.

Now lets apply this to the statement g<T>(p);. When parsing the function template func, the statement g<T>(p); is encountered. Since g is a dependent qualified name, according to the above quoted statement, the name g is looked up using ordinary lookup rules. This is so that the compiler can decide whether the name g is a template. But since there is no declaration for a function template named g before this point, the first angle bracket < is treated as a less than symbol and hence produces the error you mentioned. Also, note that ADL is done in second phase. But for that to happen we must first successfully parse the generic definition of function func.[source: C Templates: The Complete guide: Page 250 second last paragraph]

Note that compilers are allowed to delay error until instantiation which is why some compilers compiles your code without any error. Demo.

Case 2

Here we consider the statement g(p);.

template<typename T> void func(T p) {
g(p); // NO ERROR
}
int main()
{

}

In this case also, the name g is an unqualified dependent name. So according to the quoted statement from the beginning of my answer, the name g is looked up using ordinary lookup rules. But since there is no g visible at this point we have an error. There are two things to note here:

  1. Since this time you have not explicitly(by using the angle brackets) called g, there is no syntax error.
  2. And since there are no syntax error in this case and there are no POI for func in your program, so here there are no errors to delay and the program compiles fine. However, if you instantiate func then you'll get error at instantiation time saying g was not declared.

CodePudding user response:

template uses a Two-phase name lookup.

First, at the point of the template definition, the template is checked for syntax.

and so g(p); is correct (from syntax point of view) (assuming a function g found by ADL).

For g<T>(p);, we have (until C 20):

Although a function call can be resolved through ADL even if ordinary lookup finds nothing, a function call to a function template with explicitly-specified template arguments requires that there is a declaration of the template found by ordinary lookup (otherwise, it is a syntax error to encounter an unknown name followed by a less-than character)

g<T>(p); is not correct, (as parsed only as (g < T) > p; (T is a type, so it is wrong)).

If there exists any template function g, then g might be considered as template, and code would be correct from syntax point of view (even if template parameter won't match).

  • Related