Wie kann ich dafür sorgen, dass meine Größe der Summenstruktur mit einem leeren Parameterpaket funktioniert?

8

Ich habe diese variable Struktur zur Bestimmung der Summe der Größe aller übergebenen Typen:

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

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

Die Frage ist, wie ich dies ändere, damit es an einem leeren Parameterpaket arbeiten und zurückkehren kann 0.

z.B TotalSizeOf<>::value

Derzeit erhalte ich den Fehler error: wrong number of template arguments (0, should be at least 1)

Ich habe nur C ++ 14 zur Verfügung.

Salgar
quelle
Könnten Sie ein Standardvorlagenargument definieren und eine Klasse erstellen, die für sizeof 0 zurückgibt? aber ich denke der zweite ist unmöglich. Möglicherweise mit einem leeren Array wie hier: stackoverflow.com/questions/47352663/…
RoQuOTriX

Antworten:

12

Sie müssen sich einfach auch darauf spezialisieren <>

Beispiel:

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
quelle
Vielen Dank, ich habe mich falsch spezialisiert, weil ich nicht wie Sie die oberste Zeile als nicht spezialisierte Basisversion hatte.
Salgar
@Salgar: Sehr häufiger Fehler :-) Dies führt zu "Spezialisierung auf falsche Anzahl von Vorlagenargumenten" ... Übrigens: Als ich das Beispiel schrieb, stoße ich auch darauf :-)
Klaus
5

Mit C ++ 17 können Sie dies ohne aufwändige Metaprogrammierung von Vorlagen mithilfe von Fold-Ausdrücken erhalten:

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

Dies sollte auch beim Kompilieren effizienter sein (natürlich sind diese zur Laufzeit gleich).

PS: Lesen Sie einfach, dass Sie nur C ++ 14 haben, aber lassen Sie dies hier stehen, da ich es schön zu sehen finde, dass wir in neueren C ++ - Versionen weniger gezwungen sind, umständliches TMP durchzuführen.

Nachtrag: Weniger elegant als C ++ 17, aber C ++ 14 und ziemlich tmp-frei

#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
quelle
1
Ja, das ist ordentlich. Ich freue mich darauf, Fold-Ausdrücke verwenden zu können
Salgar