I have the following code that I use to get size of all primitive types in the pack (I treat floats and doubles in a special way), but my program fails to compile when the pack is empty.
// terminating general case for T being anything else
template <class T>
size_t getSize()
{
return sizeof(T);
}
// terminating special case for T=double
template<>
size_t getSize<double>()
{
return SIZEOF_DOUBLE;
}
// terminating special case for T=float
template<>
size_t getSize<float>()
{
return SIZEOF_FLOAT;
}
// recursive case
template <class T, class U, class ...S>
size_t getSize()
{
return getSize<T>() + getSize<U, S...>();
}
I want getSize
to return 0
when called like
template <class ...T>
void foo(T... arg)
{
size_t sizeOfTypes = getSize<T...>();
}
with T={}
, i.e. foo
is called like foo<>();
.
Note that I don't want to modify the way the foo
is called, the angle brackets have to stay there. Preferably I'd like to have getSize
modified, because I use it in several functions other than foo
. Modify foo
as the last resort.
Another approach to solve this would be to use a couple of little structs like
template<typename T>
struct GetTypeSize
{
enum { value = sizeof(T) };
};
template<>
struct GetTypeSize<float>
{
enum { value = SIZEOF_FLOAT };
};
template<>
struct GetTypeSize<double>
{
enum { value = SIZEOF_DOUBLE };
};
template<typename...>
struct GetSize
{
enum { value = 0 };
};
template<typename Head, typename... Tail>
struct GetSize<Head, Tail...>
{
enum { value = GetTypeSize<Head>::value + GetSize<Tail...>::value };
};
template<typename... T>
void foo(T... arg)
{
size_t sizeOfTypes = GetSize<T...>::value;
}
This has the advantage of beeing evaluated (summed up) during compile time.
I used two types of structs. One for doing the recursion (GetSize) and another for getting the actual size of the types (GetTypeSize). The specialization of GetSize<Head, Tail...>
is instantiated as long as there is a head (the pack is not empty) and adds the size of the type in Head to the recursive call of GetSize<Tail...>
. Once there is no Head the fallback GetSize template is used.
For an instantiation of
GetSize<int, double, char>
it results in
GetTypeSize<int>::value + GetTypeSize<double>::value + GetTypeSize<char>::value + GetSize<>::value
which then is
sizeof(int) + SIZEOF_DOUBLE + sizeof(char) + 0