2012-09-25 26 views
6

En tiempo de compilación en C++ 11 en una función de plantilla que toma 2 parámetros de plantilla, los cuales deben ser tipos enteros sin signo, me gustaría tener una variable local que tenga el tipo de cualquiera de los dos parámetros de plantilla tiene más bits. En C++ 03 podría escribir algo como:C++ 11 forma de escribir la plantilla para elegir un tipo entero más grande?

template<bool, class T, class U> 
struct pick_first; 

template<class T, class U> 
struct pick_first<true, T, U> { 
    typedef T type; 
}; 

template<class T, class U> 
struct pick_first<false, T, U> { 
    typedef U type; 
}; 

template<class T, class U> 
struct pick_bigger { 
    typedef typename pick_first<(sizeof(T) >= sizeof(U)), T, U>::type type; 
}; 

// usage 
template<class uintX_t, class uintY_t> 
void foo() { 
    typename pick_bigger<uintX_t, uintY_t>::type mylocal = 0; 
    // insert doing stuff with mylocal here 
} 

¿Puedo aprovechar ninguna de las nuevas características de C++ 11 para hacer esta simple? Sé que podría usar plantillas variadic para que funcione con más que solo pares de tipos, y en lugar de utilizar pick_first podría escribir muchas especializaciones para que funcione con los nuevos int_leastX_t y int_fastX_t tipos. Pero tengo curiosidad si hay un mejor acercamiento a esto. Tal vez de alguna manera aprovechando auto/constexpr/decltype?

+4

¿Has considerado 'std :: common_type' –

+0

No había oído hablar de std :: common_type! Muy interesante. Esto funcionaría para mí. Sin embargo, deberías publicar una respuesta como respuesta para poder votar;) –

+0

@ DavidRodríguez-dribeas Pero 'common_type' no siempre funcionará debido a las reglas de promoción de enteros. Por ejemplo, 'std :: common_type :: type' es' int', que puede ser más grande que cualquiera de los 2 tipos. – Praetorian

Respuesta

7

Su pick_first se acaba de std :: condicional en C++ 11, por lo que podría escribir

template<class T, class U> 
struct wider { 
    using type = typename std::conditional<sizeof(T) >= sizeof(U), T, U>::type; // I'm using the C++11 type alias feature 1) to educate people about them and 2) because I like them better than typedefs. 
}; 

Si lo que desea es un tipo adecuado para sostener el resultado de una expresión que incluya ambos tipos, y no lo hace necesariamente tienen exactamente uno de los dos tipos continuación std::common_type, o tal vez auto, es la mejor solución:

template<class uintX_t, class uintY_t> 
void foo() { 
    typename std::common_type<uintX_t, uintY_t>::type mylocal = 0; 
    // insert doing stuff with mylocal here 
} 

// or 
template<class uintX_t, class uintY_t> 
void foo(uintX_t x, uintY_t y) { 
    auto mylocal = x + y; 
} 

y su implementación de pick_bigger falta un typename allí: typedef typename pick_first<(sizeof(T) >= sizeof(U)), T, U>::type type;

+0

Esto agrega una magia de plantilla intrincada, con código que no se compila con el compilador más utilizado, para producir un tipo subóptimo para la variable local para la que OP quiere un tipo. Eso es extremadamente tonto. Pero parece inteligente. –

+0

Guau, no estaba al tanto de std :: condicional tampoco, dulce. –

+0

@JosephGarvin Puede consultar http://en.cppreference.com/w/cpp/types para ver todos los nuevos rasgos de tipo. – bames53

1

dado que ambos tipos no están firmados, solo haga decltype(T1() + T2()).

+5

Esto tiene el mismo problema con la promoción de enteros que common_type, decltype (char() + short()) es int. Si eso es aceptable, solo el uso de common_type directamente es la mejor solución. – bames53

+0

@ barnes54: common_type agrega una dependencia de encabezado. no hay necesidad de eso. en cuanto a obtener 'unsigned int' en lugar de' short', el OP está pidiendo un tipo adecuado para una variable local. el tipo más adecuado es el que puede almacenar resultados de expresiones directamente sin conversión. eso es lo que produce esta expresión. y ese tipo más adecuado no es lo que produce un selector de plantillas tonto y sobrediseñado. –

+0

@downvoter: explique su voto negativo. Lo sé, la explicación * sonará * razonable, al igual que el triple comentario votado de barnes53, y probablemente ni siquiera voy a comentar sobre él (ya discutido). pero solo por completitud. –

Cuestiones relacionadas