¿Cómo hago que mi estructura sizeof sum funcione con un paquete de parámetros vacío?

8

Tengo esta estructura variada para determinar la suma del tamaño de todos los tipos pasados:

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)> {};

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

La pregunta es, ¿cómo modifico esto para permitir que funcione en un paquete de parámetros vacío 0?

p.ej TotalSizeOf<>::value

Actualmente recibo el error error: wrong number of template arguments (0, should be at least 1)

Solo tengo C ++ 14 disponible.

Salgar
fuente
¿Podría definir un argumento de plantilla predeterminado y crear una clase que devuelva 0 para sizeof? pero creo que lo segundo es imposible. Tal vez con una matriz vacía como aquí: stackoverflow.com/questions/47352663/…
RoQuOTriX

Respuestas:

12

Simplemente debes especializarte también para <>

Ejemplo:

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;
}
Klaus
fuente
Gracias, me estaba especializando incorrectamente porque no tenía la línea superior como la versión básica no especializada como tú.
Salgar
@Salgar: Falla bastante común :-) Esto resulta en "especializarse para un número incorrecto de argumentos de plantilla" ... Por cierto: mientras escribía el ejemplo, también me encuentro con él :-)
Klaus
5

Con C ++ 17 puede obtener esto sin metaprogramación de plantilla elaborada, utilizando expresiones de plegado

#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;
}

Esto también debería ser más eficiente al compilar (por supuesto, en tiempo de ejecución, son lo mismo).

PD: Acabo de leer que solo tienes C ++ 14, pero dejaré que esto permanezca aquí, ya que creo que es agradable ver que estamos menos obligados a hacer TMP incómodo en las nuevas versiones de C ++.

Anexo: Menos elegante que C ++ 17, pero C ++ 14 y prácticamente libre de tmp

#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;
}
n314159
fuente
1
Sí, eso está bien. Espero poder usar expresiones de pliegue
Salgar