Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function templates: extern template vs explicit specialisation

Consider the following function template declaration:

template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);

There is only one possible valid instantiation of this template, namely with T = int. I'd like to put this definition in an implementation file. I can think of two possible ways of doing so. (If you're wondering why on earth I'd do this rather than just saying void foo(int i), it's because the template version prevents implicit conversions at the call site.)

Approach 1:

I can use an extern template declaration to tell other TUs that foo<int>() is instantiated elsewhere:

// In foo.hpp
template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);

extern template void foo(int);

// In foo.cpp
template <typename T, typename>
void foo(T i) { ... } // full template definition

template void foo(int); // explicit instantiation with T = int

Approach 2:

I can provide an explicit specialisation for the int case:

// In foo.hpp
template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);

template <> void foo(int i); // explicit specialisation declaration (*)

// In foo.cpp
template <>
void foo(int i) { ... } // explicit specialisation definition

Questions:

  • Are both of these approaches legal, or am I unintentionally relying on UB?
  • If both are legal, is there a good reason to prefer one approach over the other, other than the fact that approach 2 is very slightly less typing? Both GCC and Clang work equally well with either approach.
  • For approach 2, is the explicit specialisation declaration at (*) actually required? Again, both GCC and Clang are perfectly happy if it's omitted, but doing so makes me uncomfortable about the fact that a call to foo(3) in another TU is an implicit instantiation of a template with no definition visible, and no promise that such a definition exists elsewhere.
like image 783
Tristan Brindle Avatar asked Mar 30 '17 15:03

Tristan Brindle


People also ask

What is explicit template specialization?

Explicit (full) specializationAllows customizing the template code for a given set of template arguments.

What are the differences between function template and template function?

Function Template is the correct terminology (a template to instantiate functions from). Template Function is a colloquial synonym. So, there's no difference whatsoever.

What is extern template?

Extern templatesA template specialization can be explicitly declared as a way to suppress multiple instantiations. For example: #include "MyVector. h" extern template class MyVector<int>; // Suppresses implicit instantiation below --

What is the difference between generic class template and specialization template?

Key differences between generics and C++ templates: Generics are generic until the types are substituted for them at runtime. Templates are specialized at compile time so they are not still parameterized types at runtime. The common language runtime specifically supports generics in MSIL.


1 Answers

There is a third approach. In approach 3 you specify the function you want to have and the you add a template overload and mark that as delete. That looks like

void foo(int i)
{
    // stuff
}

template <typename T>
void foo(T t) = delete;

Since the template version will match all types exactly it will be preferred in all cases except int since a non template exact match is preferred to a template one. So you will only be able to call foo with an int and all other types will give you an error that they are trying to call the deleted function void foo(T t).

Live Example

like image 55
NathanOliver Avatar answered Sep 22 '22 17:09

NathanOliver