2012-10-01 19 views
6

Considerando la seguente funzione:sizeof modello variadic (somma di sizeof di tutti gli elementi)

template<typename... List> 
inline unsigned int myFunction(const List&... list) 
{ 
    return /* SOMETHING */; 
} 

Qual è la cosa più semplice da mettere al posto di /* SOMETHING */ al fine di restituire la somma di sizeof tutti gli argomenti?

Per esempio myFunction(int, char, double) = 4+1+8 = 13

risposta

13
unsigned myFunction() {return 0;} 

template <typename Head, typename... Tail> 
unsigned myFunction(const Head & head, const Tail &... tail) { 
    return sizeof head + myFunction(tail...); 
} 
+0

Smart (+1) - con 'inline' sarà ancora più intelligente. – PiotrNycz

+2

@PiotrNycz: 'inline' come una cosa di ottimizzazione, è solo un suggerimento. Niente di più. Personalmente apprezzo molto più la chiarezza del codice che l'allusione, quindi "in linea" dovrebbe essere meglio riservato per il suo unico effetto garantito, vale a dire il suo effetto ODR. –

+7

@PiotrNycz: Sì, se è necessario definire il sovraccarico non di modello in un file di intestazione, sarà necessario "in linea". Questo è piuttosto irrilevante per la domanda, però. –

4

base al largo di this comment e le seguenti osservazioni sulla questione, è possibile utilizzare questo (nota: completamente testato)

std::initializer_list<std::size_t> sizeList = {sizeof(List)...}; //sizeList should be std::initializer_list, according to the comments I linked to 
return std::accumulate(sizeList.begin(), sizeList.end(), 0); 
+0

Questo fa sorgere la domanda interessante: sarà calcolata staticamente (fino in fondo)? –

+0

Non penso che questo verrà calcolato statisticamente a meno che qualcuno non abbia realizzato una versione di constexpr di std :: accumulate, o se si dispone di un compilatore superottimizzante, ma non ho idea se un compilatore ottimizzerà così tanto. – JKor

+0

sfortunatamente non ho una versione di Clang con 'std :: initializer_list':/ –

-2

ho appena scoperto che:

template<typename... List> 
inline unsigned int myFunction(const List&... list) 
{ 
    return sizeof(std::make_tuple(list...)); 
} 

Ma:

1) Ho la garanzia che il risultato sarà sempre lo stesso su tutti i compilatori?

2) Il make_tuple si farà e sovraccarico in fase di compilazione?

+2

Questo non calcola la somma delle dimensioni. Hai la garanzia che la dimensione della tupla sia maggiore o uguale alla somma delle taglie. –

+0

Come può essere maggiore? – Vincent

+1

Un'implementazione può fare ciò che vuole. Forse più pragmaticamente, ricorda che l'unica garanzia sulla dimensione di qualcosa come 'struct {int i; doppio j; }; 'è che è almeno' sizeof (int) + sizeof (double) ', ma può essere più grande. –

2

due anni di ritardo, ma una soluzione alternativa garantite da calcolare dal compilatore (se non ti dispiace la sintassi diversa):

template < typename ... Types > 
struct SizeOf; 

template < typename TFirst > 
struct SizeOf <TFirst> 
{ 
    static const auto Value = (sizeof(TFirst)); 
}; 

template < typename TFirst, typename ... TRemaining > 
struct SizeOf < TFirst, TRemaining ... > 
{ 
    static const auto Value = (sizeof(TFirst) + SizeOf<TRemaining...>::Value); 
}; 

Usato come const int size = SizeOf<int, char, double>::Value; // 4 + 1 + 8 = 13

5

In C++ 17, usare un'espressione piega:

template<typename... List> 
inline constexpr unsigned int myFunction(const List&... list) 
{ 
    return (0 + ... + sizeof(List)); 
} 
0

Ecco un modo modello:

#include <iostream> 

template<typename T, typename ...Ts> 
class PPackSizeOf 
{ 
    public: 
    static const unsigned int size = sizeof(T) + PPackSizeOf<Ts...>::size; 
}; 


template<typename T> 
class PPackSizeOf<T> 
{ 
    public: 
    static const unsigned int size = sizeof(T); 
}; 

template<typename ...Ts> 
class FixedSizeBlock 
{ 
    private: 
     char block[PPackSizeOf<Ts...>::size]; 
    public: 

}; 

int main() 
{ 
    FixedSizeBlock<char,long> b; 
    std::cout << sizeof(b) << std::endl; 
    return 0; 
}