Reputation: 173
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
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
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_if
s 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
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