Como faço para que o meu sizeof sum struct funcione com um pacote de parâmetros vazio

8

Eu tenho essa estrutura variável para determinar a soma do tamanho de todos os tipos passados:

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

A questão é: como modifico isso para permitir que ele funcione em um pacote de parâmetros vazio, para retornar 0;

por exemplo TotalSizeOf<>::value

Atualmente, recebo o erro error: wrong number of template arguments (0, should be at least 1)

Eu só tenho C ++ 14 disponível.

Salgar
fonte
Você poderia definir um argumento de modelo padrão e criar uma classe que retornaria 0 para sizeof? mas acho que o segundo é impossível. Talvez com uma matriz vazia como aqui: stackoverflow.com/questions/47352663/…
RoQuOTriX

Respostas:

12

Você simplesmente deve se especializar também para <>

Exemplo:

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
fonte
Obrigado, eu estava me especializando incorretamente porque não tinha a linha superior como a versão básica não-especializada, como você.
Salgar 14/02
@ Salgar: Falha bastante comum :-) Isso resulta em "especializar-se em número errado de argumentos de modelo" ... BTW: Enquanto escrevia o exemplo, também me deparo com ele :-)
Klaus
5

Com o C ++ 17, você pode obter isso sem metaprogramação elaborada de modelos, usando expressões fold:

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

Isso também deve ser mais eficiente ao compilar (é claro que em tempo de execução, são os mesmos).

PS: Acabei de ler, que você só tem C ++ 14, mas deixará isso aqui, pois acho que é bom ver que somos menos obrigados a fazer TMP desajeitado nas versões mais recentes do C ++.

Adendo: menos elegante que o C ++ 17, mas o C ++ 14 e praticamente sem 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
fonte
1
Sim, isso é legal. Estou ansioso para poder usar expressões de dobra
Salgar 14/02