Template function overloading resolution different in VisualStudio and GCC

I stumbled upon an unexpected difference between GCC and VisualStudio:
Different overloaded functions are called in the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// -------- can assume this is located in 'tool.h' file --------------
// Fwd declaration helps foo( const int& ) gets called as expected by both compilers
// void foo( const int& n );

template< typename T >
void foo( const T& n )
{
  // We end here when bar(1) is called from main by GCC
  cout << "default foo T" << endl;
}

template< typename T >
void bar( const T& n )
{
  foo( n );
}

// -------- can assume this is located in 'user_overload.h' file --------------
// Specialized version
void foo( const int& n )
{
  // I expect bar(1) from main to end here...Visal studio lands here
  cout << "Overload foo int" << endl;
}

int main()
{
  // Direct call to foo: both compilers are calling overloaded foo( const int& )
  foo( 1 );

  // Indirect call to foo via bar: GCC ends calling templated (default version) 
  // while Visual studio calls 'correct' foo(const int& )
  bar( 1 );

  return 0;
}



What happens:
I expected that by calling bar(1) compiler will notice both versions of foo() and call the best match, in this case foo(const int&). That is not the case.
Note that overloaded foo(const int&) is below bar(). It seems that at that point GCC does not see overloaded version, and happily calls template version. Visual studio on the other hand has no problem finding them both.

Question 1: Why is there a difference?
Question 2: Any idea how to solve this?

Note:
If I introduce a forward declaration of foo( const int& ) before bar(), both compilers call that version correctly.
Unfortunately, that is not a solution for my problem here.
Template version is part of a library while overloaded is part of the user code. Both would be located in different (header) files and I would not like to impose #include order to the users or to be dependant on it.

TL;DR version: adding a new function declaration after template definition does not make it visible inside the template, except via ADL (if Visual Studio finds it, it has a bug)

at line 15, foo( n ) is a type-dependent expression (overload resolution of foo depends on the type of n, which is a template parameter and not known until instantiation)

at line 33, bar is instatiated and name lookup for foo runs. The lookup rules here are:
1) non-ADL lookup runs from template definition (line 15 and up)
2) ADL lookup runs from template definition (line 15 and up)
3) ADL lookup runs again, from instantiation (line 33 and up)

in your case, the argument is not a user-defined class or enum, ADL gives an empty set, and all you get is what's visible at line 15.

You could make it work if you used an enum:
1
2
3
enum MyType { one = 1 };
...
  bar( one );
Last edited on
Thanks for the reply.

I checked the C++ standard, 14.6.4.2 is exactly pointing at what you explained.
What I found on the net is that Visual Studio does not implement ADL as standard requires.

This is also coupled with another feature of VS - if template function is not used then its code is not compiled at all.

(The effect is that if you would have a syntax error inside, it will be discovered only when function/method is actually used. So, if you do not have a full coverage in your unit tests, it will not be noticed until somebody stumbles upon it)

It seems that VS does not compile unused functions until the actual point of call (line 33), instead the functions are noted and signature checked.

At that point VS goes back and starts compiling/evaluating the function content (line 15) and instantiates the templates and notices that there are two implementations of foo(...). It chooses the best match and everything works fine...

GCC on other hand works according to the C++ standard, so, sort out your order of definition please.

Links:
http://social.msdn.microsoft.com/Forums/ie/en-US/63fbf46e-25f6-4cc6-bc9b-a3772031c738/how-does-one-explain-this?forum=vcgeneral


Once again, thanks!
Topic archived. No new replies allowed.