I have a primary template function:
template <typename T, int U>
void print() {
std::cout << "int is " << U << std::endl;
}
How to make a partial specialization for function print, so that U is inferred based on a type of T?
For example:
template <typename T>
void print<T, 1>(); // If T is float
template <typename T>
void print<T, 2>(); // If T is Eigen::half
print<float>();
// Prints "int is 1"
print<Eigen::half>();
// Prints "int is 2"
CodePudding user response:
You can't partially-specialize functions, and specializations are selected after all of the template's arguments are known, so you can't do this with partial specialization.
What you can do is have a separate function template that has a single argument that simply calls through to the underlying function template:
template <typename T>
void print();
template <>
void print<float>() {
print<float, 1>();
}
template <>
void print<Eigen::half>() {
print<Eigen::half, 2>();
}
This will do what you want, but it would still be possible to override the behavior by explicitly calling print<float, 42>()
. If you don't want that to be possible, you can remove the second parameter from the base function and use a type trait to determine it:
template <typename T>
struct IntDeterminer;
template <>
struct IntDeterminer<float> : std::integral_constant<int, 1>
{};
template <>
struct IntDeterminer<Eigen::half> : std::integral_constant<int, 2>
{};
template <typename T>
void print() {
std::cout << "int is " << IntDeterminer<T>::value << std::endl;
}
CodePudding user response:
You don't. You cannot partially specialize function templates.
However, it seems like you actually don't want partial specialization but rather some mapping between T
and U
. This can be realized by specializing a trait:
#include <iostream>
template <typename T> struct U_for_T;
template <> struct U_for_T<int> { static constexpr int value = 0;};
template <> struct U_for_T<double> { static constexpr int value = 1;};
template <typename T, int U = U_for_T<T>::value>
void print() {
std::cout << "int is " << U << std::endl;
}
int main() {
print<int>();
print<double>();
}