2012-10-01 15 views
6

Teniendo en cuenta la siguiente función:sizeof plantilla variadic (suma de sizeof de todos los elementos)

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

¿Cuál es la cosa más sencilla de poner en lugar de /* SOMETHING */ con el fin de devolver la suma de todos los argumentos sizeof?

Por ejemplo myFunction(int, char, double) = 4+1+8 = 13

Respuesta

13
unsigned myFunction() {return 0;} 

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

Inteligente (+1) - con 'en línea' será aún más inteligente. – PiotrNycz

+2

@PiotrNycz: 'inline' como una cosa de optimización, es solo una pista. Nada mas. Personalmente, valoro la claridad de los códigos mucho más que esa alusión, y luego 'inline' debería reservarse para su único efecto garantizado, a saber, su efecto ODR. –

+7

@PiotrNycz: Sí, si necesita definir la sobrecarga sin plantilla en un archivo de encabezado, entonces tendrá que estar 'en línea'. Sin embargo, eso es bastante irrelevante para la pregunta. –

4

Basado fuera de this comment y los siguientes comentarios sobre la cuestión, se podrían utilizar esta (nota: no está comprobado)

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

Esto plantea la pregunta interesante: ¿esto se calculará estáticamente (todo el camino hacia abajo)? –

+0

No creo que esto se compute estáticamente a menos que alguien haga una versión constexpr de std :: accumulate, o si tiene un compilador súper optimizado, pero no tengo idea de si algún compilador optimizará tanto. – JKor

+0

lamentablemente no tengo una versión de Clang con 'std :: initializer_list':/ –

-2

que acabo de descubrir que:

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

Pero:

1) ¿Tengo la garantía de que el resultado siempre será el mismo en todos los compiladores?

2) ¿Hará la make_tuple y la sobrecarga en tiempo de compilación?

+2

Esto no calcula la suma de los tamaños. Usted tiene una garantía de que el tamaño de la tupla es mayor o igual a la suma de los tamaños. –

+0

¿Cómo puede ser mayor? – Vincent

+1

Se permite que una implementación haga lo que quiera. Quizás más pragmáticamente, recuerde que la única garantía en el tamaño de algo como 'struct {int i; doble j; }; 'es que es al menos' sizeof (int) + sizeof (double) ', pero puede ser más grande. –

2

dos años de retraso, pero una solución alternativa garantizada para ser computada por el compilador (si no te importa la sintaxis diferente):

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

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

5

En C++ 17, utilizar una expresión doble:

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

Aquí está una manera plantilla:

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