Slava Slava - 9 days ago 5
C++ Question

Declare function after template defined

Let's say I have a template function:

template <class T>
void tfoo( T t )
{
foo( t );
}


later I want to use it with a type, so I declare/define a function and try to call it:

void foo( int );

int main()
{
tfoo(1);
}


and I am getting error from g++:


‘foo’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
foo( t );


why it cannot find
void foo(int)
at the point of instantiation? It is declared at that point. Is there a way to make it work (without moving declaration of
foo
before template)?

AnT AnT
Answer

foo in your case is a dependent name, since function choice depends on the type if the argument and the argument type depends on the template parameter.

However, the only difference between dependent and non-dependent lookup is that in case of dependent lookup ADL-nominated namespaces and only ADL-nominated namespaces are extended with extra names. (These extra names appear after the template declaration).

(By ADL-nominated namespace I refer to namespace associated with function argument type and therefore brought into consideration by the rules of dependent name lookup. See "3.4.2 Argument-dependent name lookup")

In your case the argument has type int. int is a fundamental type. Fundamental types do not have associated namespaces (see "3.4.2 Argument-dependent name lookup"), which means that it does not nominate any namespace through ADL. In your example ADL is not involved at all. Dependent name lookup for foo in this case is no different from non-dependent lookup. It will not be able to see your foo, since it is declared below the template.

Note the difference with the following example

template <class T> void tfoo( T t )
{
    foo( t );
}

struct S {};

void foo(S s) {}

int main()
{
    S s;
    tfoo(s);
}

This code will compile since argument type S is a class type. It has an associated namespace - the global one - and it adds (nominates) that global namespace for dependent name lookup. Such ADL-nominated namespaces are seen by dependent lookup in their updated form (as seen from the point of the call). This is why the lookup can see foo and completes successfully.


It is a rather widespread misconception when people believe that the second phase of so called "two-phase lookup" should be able to see everything that was additionally declared below template definition all the way to the point of instantiation (point of the call in this case).

No, the second phase does not see everything. It can see the extra stuff only in namespaces associated with function arguments. All other namespaces do not get updated. They are seen as if observed from the point of template definition.