I am trying to specialize a function of two template arguments, when template argument types are same. I do it the following way:
#include <iostream>
#include <type_traits>
using namespace std;
template<typename U, typename T>
int fun( U& u, T t );
template<>
inline
int fun( int& u, float t )
{
cout << "int, float" << endl;
return 0;
}
template<typename U, typename T>
inline
int fun( U& u, typename std::enable_if<std::is_same<U, T>::value ,T>::type t )
{
cout << "U == T" << endl;
return 0;
}
int main()
{
int a;
float b1, b2;
fun(a, b1);
fun(b1, b2);
return 0;
}
This code compiles fine (GCC 4.8.2) but linker gives undefined refernces to all the fun
calls when U
and T
are same type. Why doesn't it work?
Linker output:
g++ -std=c++11 test.cpp
/tmp/cc7HWboz.o: In function `main':
test.cpp:(.text+0x66): undefined reference to `int fun<float, float>(float&, float)'
collect2: error: ld returned 1 exit status
THE PROBLEM
Your fun
that is using std::enable_if
to protect instatiation from two types that differs has a major problem; it cannot implicitly deduce type T
.
This means that when you are calling fun
with b1
and b2
as parameters you are instantiating template<typename U, typename T> int fun( U& u, T t )
, which hasn't got a definition.. hence the linker error.
THE SOLUTION
There are many alternatives to the code written below, but I reckon this might clear out some confusion.
template<
typename U,
typename T,
typename = typename std::enable_if<std::is_same<U, T>::value>::type
>
inline int fun( U& u, T t)
{
cout << "U == T" << endl;
return 0;
}
inline int fun( int& u, float t )
{
cout << "int, float" << endl;
return 0;
}
In the above the compiler can deduce both T
and U
in our template, there is also no need for an explicit specialization of said template; we can make use of C++'s rules for overloading and have the compiler decide when int&, float
is a better match than deducing U&, T
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With