Home > Software design >  C partial template function specialization
C partial template function specialization

Time:09-22

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>();
}

Demo

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;
}

Demo

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>();
}
  • Related