Template function call confused by function with incorrect signature declared before template

The following code is not accepted by GCC 4.6:

void F(int x,char y) { } template<typename T> void G(T t) { F(t); } void F(int x) { } int main() { G(5); return 0; } 

Should it be?

If not, does anyone have a good idea for the job? The real-world scenario where this happens is where G is part of the library for solving a specific problem requiring an auxiliary function provided by the user called F. However, for different types of problems, F takes a different number of parameters. A few examples of the implementation of F come with the library.

What happens is that, depending on the # include-order used by the client, only the “wrong view” F can be seen when the template is declared, and GCC then refuses, without waiting for the user to be given, correctly, F is defined. This is even though the creation of the template occurs after determining the correct F.

Update: Yes, I know that this works if all F declarations occur before G or all F declarations occur after G. However, this does not help me much.

Update: in the code this minimal example is adapted, F is really called "read". And the first reading announcement has nothing to do with the second. The first declaration is in one header file, and the second is in another. I don’t want to introduce “strange” rules regarding the order of include files, especially when the “read” versions have nothing to do with each other.

+4
source share
4 answers

When an instance is created, only an argument-dependent search is performed. You can fix your case using an argument whose type is in the namespace of your F

 void F(int x,char y) { } template<typename T> void G(T t) { F(t); } void F(int x) { } template<typename T> struct wrapper { operator T() const { return t; } T t; }; template<typename T> wrapper<T> make_wrapper(T t) { wrapper<T> w = { t }; return w; } int main() { G(make_wrapper(5)); return 0; } 
+4
source

One possible workaround is to ensure that the void F(int x) declaration is available before template<typename T> void G(T t);

 void F(int x); template<typename T> void G(T t) { .... } 

In your example, the dependent name is F(int) , so it appears in the second phase of the two-phase search. However, the search rules. specified in item 14.6.4 of project n3337, specify that the name should be visible at the template definition point or in the namespace associated with the types of function arguments (search dependent on arguments):

When resolving dependent names, names from the following sources are taken into account:

- Ads that are visible at the template definition point.

- declarations from namespaces associated with types of function arguments as from context context (14.6.4.1) and definition context.

So an alternative approach is to transform the function into a T namespace.

+1
source

Try placing an overload of F(int) above G

 void F(int x) {} template <typename T> void G(T t) { F(t); } // works 

Functions do not rise; you must either prototype or define them before using them.

0
source

If not, does anyone have a good idea for the job?

At the moment you define this template, the only F() that the compiler knows is void F(int x,char y) , which clearly does not match the use in G(T t) .

The solution is simple: define or declare void F(int x) before by defining template<typename T> void G(T t) .

0
source

All Articles