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.
#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:
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.
how does the C++ standard resolves this ambiguity.
From temp.over.link#1:
1. It is possible to overload function templates so that two different function template specializations have the same type.
2. Such specializations are distinct functions and do not violate the one-definition rule.
(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.
How does the C++ standard allows the first overload to be selected/preferred instead of the second.
To answer the second question, during overload resolution the call func(2,2)
inside function init
in source2.cpp was already bound to the instantiated version from the second overload. Similarly, for the call expression func(2,2)
inside main.cpp, it is bound to the instantiated version from the first overload.
Thus, when init
is called from inside main.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.