Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Templated function specialization: linker error

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
like image 564
user2052436 Avatar asked May 25 '14 19:05

user2052436


1 Answers

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.

like image 107
Filip Roséen - refp Avatar answered Oct 23 '22 18:10

Filip Roséen - refp