Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make my sizeof sum struct work with an empty parameter pack

Tags:

c++

c++14

I have this variadic struct for determining the sum of the sizeof all the types passed in:

template <typename U, typename... T> struct TotalSizeOf 
    : std::integral_constant<size_t, sizeof(U) + TotalSizeOf<T...>::value> {};

template <typename U> struct TotalSizeOf<U> 
    : std::integral_constant<size_t, sizeof(U)> {};

Usage: TotalSizeOf<double, int, char>::value

The question is, how do I modify this to allow it to work on an empty parameter pack, to return 0;

e.g. TotalSizeOf<>::value

Currently, I get the error error: wrong number of template arguments (0, should be at least 1)

I only have C++14 available.

like image 574
Salgar Avatar asked Feb 14 '20 12:02

Salgar


2 Answers

You simply must specialize also for <>

Example:

template < typename... T> struct TotalSizeOf;

template < typename U, typename... T> struct TotalSizeOf<U, T...>
: std::integral_constant<size_t, sizeof(U) + TotalSizeOf<T...>::value> {};

template <> struct TotalSizeOf<> :
std::integral_constant<size_t, 0 > { };

int main()
{
    std::cout << TotalSizeOf< int, char>::value << std::endl;
    std::cout << TotalSizeOf< char>::value << std::endl;
    std::cout << TotalSizeOf< >::value << std::endl;
}
like image 140
Klaus Avatar answered Nov 15 '22 18:11

Klaus


With C++17 you can get this without elaborate template metaprogramming, using fold expressions:

#include <iostream>
#include <type_traits>

template<class... T> 
struct TotalSizeOf: std::integral_constant<std::size_t, (0 + ... + sizeof(T))> {};

int main()
{
    std::cout << TotalSizeOf< int, char>::value << std::endl;
    std::cout << TotalSizeOf< char>::value << std::endl;
    std::cout << TotalSizeOf< >::value << std::endl;
}

This should also be more efficient when compiling (of course at runtime, these are the same).

PS: Just read, that you only have C++14, but will let this stand here, since I think it is nice to see, that we are less forced to do awkward TMP in newer C++ versions.

Addendum: Less elegant than C++17, but C++14 and pretty much tmp-free

#include <iostream>
#include <type_traits>
#include <initializer_list>

constexpr size_t sum(std::initializer_list<size_t> arr) {
    // Accumulate is sadly not constexpr in C++14
    auto ret = 0ul;
    for(auto i: arr) {
        ret += i;
    }
    return ret;
}

template<class... T> 
struct TotalSizeOf: std::integral_constant<std::size_t, sum({sizeof(T)...})> {};

int main()
{
    std::cout << TotalSizeOf< int, char>::value << std::endl;
    std::cout << TotalSizeOf< char>::value << std::endl;
    std::cout << TotalSizeOf< >::value << std::endl;
}
like image 32
n314159 Avatar answered Nov 15 '22 20:11

n314159