Template Function Specialization for Integer Types

Template Function Specialization for Integer Types

Use SFINAE

// For all types except integral types:
template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type f(T t)
{
// ...
}

// For integral types only:
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type f(T t)
{
// ...
}

Note that you will have to include the full std::enable_if return value even for the declaration.

C++17 update:

// For all types except integral types:
template<typename T>
std::enable_if_t<!std::is_integral_v<T>> f(T t)
{
// ...
}

// For integral types only:
template<typename T>
std::enable_if_t<std::is_integral_v<T>> f(T t)
{
// ...
}

How does template specialization with integer types work?

1) If long and long long is the same type, why does the compiler allow both specializations to coexist?

Because long and long long can be implemented over the same low level type but, from the point of view of the language, are different fundamental types.

2) Why adding a specialization for int64_t produces an error?

Because std::int64_t isn't an arithmetic fundamental type but is an alias (defined through typedef or using) of another type

3) Why foo<int64_t> resolves as foo<long long> and not foo<long>?

Because, in your platform, std::int64_t is defined as an alias for long long, not for long (or an alias for an alias...); so, in your platform, std::int64_t is long long; in different platform, you can have different results

4) Why foo<ssize_t> resolves as foo<long> and not foo<long long>?

Same as std::int64_t: the type ssize_t (not a standard type) is an alias (in your platform) for long, not for long long

5) Why foo<uint64_t> does not use specialization foo<size_t>?

Because std::uint64_t and std::size_t aren't fundamental arithmetic types but both are alias for other types (unsigned long and unsigned long long, I suppose) and, in your platform, they are alias of different types

6) Is the behavior that I observe here universal, or machine-specific? How can I be sure that this code is portable?

With exception for point (1) (that is ever true because the difference between long and long long is part of the language), is heavily platform dependent.

But it's possible to manage it using, by example, std::is_same and other type traits.

C++ Templates - Different Specialization for Floating and Integral types

You could use template overloads with SFINAE. e.g.

template<typename To, typename From>
typename std::enable_if<std::is_integral<To>::value, To>::type bar(From in) {
...
}

template<typename To, typename From>
typename std::enable_if<std::is_floating_point<To>::value, To>::type bar(From in) {
...
}

BTW I suggest to change the declaration order of the template parameter From and To, then you can just specify the 1st template argument explicitly when calling them. Such as bar<int>(...); and bar<float>(...);.

LIVE

If you want to get a more clear message for types other than integral and float point types, you can add another overload. e.g.

template<class T> struct dependent_false : std::false_type {};

template<typename To, typename From>
typename std::enable_if<!std::is_integral<To>::value && !std::is_floating_point<To>::value, To>::type bar(From in) {
static_assert(dependent_false<To>::value, "Types must be integral or floating point types.");
}

C++ template specialization - delegating other integer types to uint64_t

The problem is that all template-arguments of a template-specialization must be deducible from the base-template, not from each other.

If you can add a dummy-argument to the base-template, or do the specialization in a base under your control, you are golden though:

template <typename T, class = void>
struct custom_hash;
template <>
struct custom_hash<uint64_t>
{ size_t operator()(uint64_t x) const { /* ... */ }};
template <class T>
struct custom_hash<T, std::enable_if_t<std::is_integral<T>() && sizeof(T) <= sizeof(uint64_t)>
{ size_t operator()(int x) const { custom_hash<uint64_t> h; return h(uint64_t(x)); }};

Partial specialization of templates with integer parameters

As a rule any form of partial template specialisation is not allowed for functions. However it is allowed for classes. So the solution is simply to move your function to a static member of a templated holder class.

If you need to deduce the template arguments, you can then just create a wrapper function that calls the templated class.

The result is something like this:

template<int Index, typename Tpl>
class CalcInterleaveByteOffsetImpl
{
static size_t CalcInterleaveByteOffset(const Tpl &t)
{
// This is OK it calls the wrapper function
// You could also do
// size_t prevOffset = CalcInterleaveByteOffsetImpl<Index - 1, Tpl>::CalcInterleaveByteOffset(t);
size_t prevOffset = ::CalcInterleaveByteOffset<Index - 1>(t);
return prevOffset + sizeof(Tpl);
}
};

template<typename Tpl>
class CalcInterleaveByteOffsetImpl<0, Tpl>
{
static size_t CalcInterleaveByteOffset(const Tpl &t)
{
return 0;
}
};

template<int Index, typename Tpl>
size_t CalcInterleaveByteOffset(const Tpl &t)
{
return CalcInterlaveByteOffsetImpl<Index,Tpl>::CalcInterleaveByteOffset(t);
}

template specialization for special value of integer parameter

I think you want:

template<int COUNT, typename ...Ts> struct RemoveFirstElementsImpl;

template<>
struct RemoveFirstElementsImpl<0>
{
using type = std::tuple<>;
};

template<typename T, typename ...Ts>
struct RemoveFirstElementsImpl<0, T, Ts...>
{
using type = std::tuple<T, Ts...>;
};

template<int N, typename T, typename ...Ts>
struct RemoveFirstElementsImpl<N, T, Ts...>
{
using type = typename RemoveFirstElementsImpl<N - 1, Ts...>::type;
};

Live Demo

C++ template function explicit specialization with multiple template types

template<bool B, typename T>
void foo(T const&)
{
static_assert(false, "not implemented");
}

template<bool B>
void foo(short)
{
printf("it's a short!\n");
}

However, this is not really specialisation, but overloading, which is completely appropriate. In fact, you could omit the general case.

How can I specialize a C++ template for multiple ranges of integer values?

To answer your edit and make your original code work.

template<int BITS>
class MyClass {
using int_type =
typename std::conditional< BITS <= 8, uint8_t,
typename std::conditional< BITS <= 16, uint16_t,
typename std::conditional< BITS <= 32, uint32_t, uint64_t >::type >::type >::type;
public:
int_type i;
};

Integer range based specialization of template method in template class

This should work:

template<int value, class T, class X>
struct Helper {
static uint64_t foo(uint64_t param) {
return Helper<value - 1, T, X>::foo(param);
}
};

template<class T, class X>
struct Helper<0, T, X> {
static uint64_t foo(uint64_t param) {
static_assert(sizeof(T) == 0, "Unsupported type combination.");
return 0;
}
};

template<>
uint64_t Helper<1, uint8_t, uint16_t>::foo(uint64_t param) {
return param * 1000;
}

template<>
uint64_t Helper<7, uint8_t, uint16_t>::foo(uint64_t param) {
return param * 7000;
}

template<int value>
class MyClass {
template<class T, class X>
uint64_t foo() {
return Helper<value, T, X>::foo(m_member);
}

uint64_t m_member;
};


Related Topics



Leave a reply



Submit