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:
(*)
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.Explicit (full) specializationAllows customizing the template code for a given set of template arguments.
Function Template is the correct terminology (a template to instantiate functions from). Template Function is a colloquial synonym. So, there's no difference whatsoever.
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 --
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.
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
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