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
andlong 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 asfoo<long long>
and notfoo<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 asfoo<long>
and notfoo<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 specializationfoo<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
How to Track Memory Allocations in C++ (Especially New/Delete)
Reading an Application's Manifest File
How to Create a C++ Boost Undirected Graph and Traverse It in Depth First Search (Dfs) Order
How to Extend a Lexical Cast to Support Enumerated Types
Convert a C++ Program to a Windows Service
Is It Wise to Ignore Gcc/Clang's "-Wmissing-Braces" Warning
Why Does Valgrind Say Basic Sdl Program Is Leaking Memory
Why Are '&Array' and 'Array' Pointing to the Same Address
Exact Decimal Datatype for C++
Static and Dynamic/Shared Linking with Mingw
Why Isn't There an Operator[] for a Std::List
How to Determine the Amount of Linux System Ram in C++
Literal Initialization for Const References
Lambda Capture and Parameter with Same Name - Who Shadows the Other? (Clang VS Gcc)
How to Produce Deterministic Binary Output with G++