Search code examples
c++templatesexplicit-instantiationforwarding-reference

Explicit template instantiation and forwarding references


Recently, I was discussing with students the possibilities of restriction of types for templates that uses forwarding references. I knew about comparing types by is_same together with static_assert or enable_if, but we also talked about explicit template instantiation.

The following example works for me with GCC:

f.h:

template <typename T>              
void f(T&& param); // declaration  

f.cpp:

#include <iostream>

template <typename T>
void f(T&& param) { std::cout << param << std::endl; }

// explicit instantiations:
template void f<int>(int&&);
template void f<int&>(int&);

main.cpp:

#include "f.h"      

int main() { 
   f(1);              
// f('1'); // LINKER ERROR   

   int i = 2;         
   f(i);              
}                     

I am not an expert in explicit template instantiations, so I just wonder whether such a solution is portable/standard-compliant. (Please, do not ask me about use cases, I don't have any. For me, it's purely an academic question.)

UPDATE

I am also a bit confused about the format of the explicit instantiation (<int>(int&&) and <int&>(int&)), but I guess that it is given by template deduction and maybe reference collapsing rules.


Solution

  • This is okay and it is portable/standard-compliant.

    This is called template specialization and you can read more on this topic here

    Template specialization is writing a specific handler for a specific invoke. In your code, you have two specializations. The first receives a rvalue reference(e.g. integer literal like 5) and returns an int.

    The second one receives a lvalue reference(e.g. the variable b who is of type int an have a value of 5) and returns a lvalue reference.

    In the default case, you're trying to print the param using std::stringstream.