Aniss Be
Aniss Be

Reputation: 173

Is it possible to overload a template function based on whether the type is an integer type or a floating point type?

I want to write template function that should just be called when the type is integer, for example int8, int16, int32, int64, uint8, uint16, uint32, uint64; and an other template function (same name) with different code just for FLOAT type float32, float64... There is anyway to do it using templates functions in C++ ? For example :

template <class T>
void fun(T b)
{
   /// Code for integer type
}


 template <class S>
void fun(S a)
{
   /// Code for floating type
}

Upvotes: 1

Views: 1161

Answers (3)

Ziyuan
Ziyuan

Reputation: 4558

According to SFINAE, we can design compilation errors for one type while letting the other go in the template substitution phase. In the case of integral type vs. floating-point type, we can make use of the bit-related operators for integers like ~. For example,

#include <iostream>

template <typename T, T=~0>
void f_(T a, int)  // additional tags for unambiguous overloading, same below
{
    std::cout << a << " is of integral type." << std::endl;
}

template <typename T>
void f_(T a, char)
{
    std::cout << a << " is of floating-point type." << std::endl;
}

template <typename T>
void f(T a)
{
    f_<T>(a, 0);
}


int main()
{
    f<char>('a');
    f<int>(0);
    f<float>(1.5f);
    f<double>(2.5);
    return 0;
}

gives

a is of integral type.
0 is of integral type.
1.5 is of floating-point type.
2.5 is of floating-point type.

Upvotes: 0

Justin
Justin

Reputation: 25327

Yes, this is possible. One way of doing this is to use SFINAE:

template <class T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
void fun(T b)
{
   /// Code for integer type
}


template <class S, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
void fun(S a)
{
   /// Code for floating type
}

Note that the 2 conditions for the enable_ifs have to be disjoint, which we can see from the documentation of std::is_integral and std::is_floating_point that they are. If they weren't, the conditions would have to look like std::is_integral_v<T> && !std::is_floating_point_v<T>.

What is happening here is that the std::enable_if_t makes one of the overloads "fail to compile" if the condition is not satisfied, which means that the overload is simply not considered due to SFINAE.


If you are using C++17, you might want to consider using if constexpr instead:

template <class T>
void fun(T b)
{
    if constexpr (std::is_integral_v<T>) {
        /// Code for integer type
    } else if constexpr (std::is_floating_point_v<T>) {
        /// Code for floating type
    }
}

Upvotes: 5

txtechhelp
txtechhelp

Reputation: 6777

Depending on what your full intent is, outside of SFINAE and std::enable_if, you can use regular function overloads and/or template specialization too:

#include <iostream>
#include <cstdint>

template < typename T >
void fun(T b)
{
    std::cout << "Generic called: " << b << std::endl;
}

void fun(int16_t b)
{
    std::cout << "int16_t: " << b << std::endl;
}

void fun(int32_t b)
{
    std::cout << "int32_t: " << b << std::endl;
}

void fun(float b)
{
    std::cout << "float: " << b << std::endl;
}

template <>
void fun<int64_t>(int64_t b)
{
    std::cout << "int64_t specialization: " << b << std::endl;
}

int main(int argc, char** argv)
{
    double dbl = 3.14159;
    float flt = 1.12345;
    int16_t i16 = 16;
    int32_t i32 = 32;
    fun(dbl);
    fun(flt);
    fun(i16);
    fun(i32);
    fun(5.555f);
    fun(32);
    fun(std::numeric_limits<int64_t>::max());
    return 0;
}

Hope that can help.

Upvotes: 3

Related Questions