I'm trying to return an int64_t
if std::is_integral<>::value
is true.
Otherwise, I would like to call to_int64t()
on the object.
My attempt below is failing because partial specialisation of function templates are not allowed.
CODE
#include <type_traits>
#include <cstdint>
template<class T,bool is_integral_type>
int64_t to_int64t( const T& t )
{
return t;
}
template<class T>
int64_t to_int64t<T,std::is_integral<T>::value>( const T& t )
{
return t;
}
template<class T>
int64_t to_int64t<T,!std::is_integral<T>::value>( const T& t )
{
return t.to_int64t();
}
int main()
{
int64_t i = 64;
auto x = to_int64t( i );
}
Function templates cannot be partially specialized and, in general, it is not a good idea to use function template specialization.
One way to achieve what you want is to use a technique called tag dispatching, which basically consists in providing a forwarder function that selects the right overload based on the value of an extra dummy argument:
#include <type_traits>
#include <cstdint>
template<class T>
int64_t to_int64t( const T& t, std::true_type )
{
return t;
}
template<class T>
int64_t to_int64t( const T& t, std::false_type )
{
return t.to_int64t();
}
template<class T>
int64_t to_int64t( const T& t )
{
return to_int64t(t, std::is_integral<T>());
}
int main()
{
int64_t i = 64;
auto x = to_int64t( i );
}
Another possibility is to use the classical SFINAE technique based on std::enable_if
. This is how that could look like (notice that, since C++11, default template arguments on function templates are allowed):
#include <type_traits>
#include <cstdint>
template<class T, typename std::enable_if<
std::is_integral<T>::value>::type* = nullptr>
int64_t to_int64t( const T& t )
{
return t;
}
template<class T, typename std::enable_if<
!std::is_integral<T>::value>::type* = nullptr>
int64_t to_int64t( const T& t )
{
return t.to_int64t();
}
int main()
{
int64_t i = 64;
auto x = to_int64t( i );
}
Yet another possibility, although more verbose, is to define helper class templates (which can be partially specialized) in a detail
namespace and provide a global forwarder - I would not use this technique for this use case, but I am showing it because it might come handy in related design situations:
#include <type_traits>
#include <cstdint>
namespace detail
{
template<class T, bool = std::is_integral<T>::value>
struct helper { };
template<class T>
struct helper<T, true>
{
static int64_t to_int64t( const T& t )
{
return t;
}
};
template<class T>
struct helper<T, false>
{
static int64_t to_int64t( const T& t )
{
return t.to_int64t();
}
};
}
template<class T>
int64_t to_int64t( const T& t )
{
return detail::helper<T>::to_int64t(t);
}
int main()
{
int64_t i = 64;
auto x = to_int64t( i );
}