I was using function templates when I noticed that moving the definition of one of the function template to a different translation unit resolves the ambiguous error
. Below are the two examples that I tried. The first example produces ambiguous error as expected but when I move the definition of one of the function template into another translation unit then the error is gone.
Example 1
#include <iostream>
template<typename X, typename Y>
void func(X, Y)
{
std::cout<<"X-Y in order version called"<<std::endl;
}
template<typename X, typename Y>
//--------v--v----->order changed
void func(Y, X)
{
std::cout<<"Y-X in order version called"<<std::endl;
}
int main()
{
func(2,2); //this is ambiguous as expected
}
Demo showing that we get ambiguous error as expected.
My question is about the second example given below:
Example 2
main.cpp
#include <iostream>
template<typename X, typename Y>
void func(X, Y)
{
std::cout<<"X-Y in order version called"<<std::endl;
}
extern void init();
int main()
{
func(2,2); //WORKS BUT HOW? How does the compiler resolves the ambiguity here
init();
}
source2.cpp
#include <iostream>
//moved to source2.cpp
template<typename X, typename Y>
//--------v--v----->order changed
void func(Y, X)
{
std::cout<<"Y-X in order version called"<<std::endl;
}
void init()
{
func(2,2);
}
The second version given above successfully compiles and produces the output:
X-Y in order version called
Y-X in order version called
My questions are:
How is the ambiguity resolved when i moved the definition of the second overload to a different translation unit? I mean we still have two intantiations(one from the overload in the main.cpp and other from the overload in source2.cpp) as before but now we're not getting the ambiguity error. So how does the C++ standard resolves this ambiguity.
How does the C++ standard allows the first overload to be selected/preferred instead of the second. I mean is there a reference in the standard that says that the instantiation from the overload in the same translation unit should be selected.
Summary
Note that my second question is about why the first version is preferred over the one in the other translation unit. While my first question is about how is the ambiguity removed when moving the definition to another translation unit.
From temp.over.link#1:
(emphasis mine)
Now, in the given example both the specializations resulting from the two overloads will have the same type
void (int, int)
and as quoted in the points above, this usage is allowed.To answer the second question, during overload resolution the call
func(2,2)
inside functioninit
in source2.cpp was already bound to the instantiated version from the second overload. Similarly, for the call expressionfunc(2,2)
inside main.cpp, it is bound to the instantiated version from the first overload. Thus, wheninit
is called from insidemain.cpp
, the second version is called. If we changed the order of the calls inside main.cpp, then the output will be reversed because the call was already bound to their respective version during overload resolution.