2011-06-30 10 views
5

Tengo un requisito que, debería usar una clase específica si un entero pasado como uno de los parámetros de la plantilla es mayor que un cierto valor. De lo contrario, debería obtener un error de tiempo de compilación ...Comparación de tiempo de compilación del parámetro de plantilla

Es algo así como lo siguiente:

enum Time { Day, Week, Month }; 

template<Time t, int length> 
class Timer 
{ 
} 

ahora que he comenzado a restringir crear instancias de Timer de tal manera que -

Timer<Day,8>, Timer<Day,9> etc. debería funcionar, pero length no puede ser menor que 8 cuando se usa con Day.

Del mismo modo, length no puede ser inferior a 10 cuando se utiliza con Week y así sucesivamente ...

por favor alguien puede ayudar con cómo esto se puede lograr en tiempo de compilación?

+0

Posible duplicado de http://stackoverflow.com/questions/3881165/how-do-i-validate-template-parameters-in-compile-time-when-a-templated-class-cont –

Respuesta

6

Pase el resultado de length >= 8 como bool plantilla argumento a la plantilla auxiliar. Proporcionar especialización para true solamente. Habiendo dicho eso, esto suena como tarea, así que te dejaré la codificación.

Cheers & hth.

+3

Yeap, the real La solución es usar 'static_assert', lo que describes es una forma de implementar' static_assert'. – sharptooth

2

La idea para este tipo de validación es generalmente entregar el trabajo a una clase de ayuda dedicada, que se especializa para cada tipo de parámetros.

template <typename T, size_t V> 
class Foo 
{ 
    static_assert(helper<T,V>::value, "Wrong Parameters"); 
}; 

Hay dos formas de realizar la validación:

// Require full specialization 
template <typename T, size_t V> struct helper: std::false_type {}; 

template <> 
struct helper<Bar,0>: std::true_type {}; 

template <> 
struct helper<Bar,4>: std::true_type {}; 


// Property like 
template <typename T, size_t V> struct helper: std::false_type {}; 

template <size_t V> 
struct helper<Bar, V>: std::integral_constant<bool, V <= 8> {}; 

Por supuesto, los que supongo instalaciones 0x C++. En C++ 03, deberá proporcionar las clases simples true_type, false_type y integral_constant usted mismo.

3

Usted puede hacer esto: Código

template<bool> 
struct rule; 

template<> 
struct rule<true> {}; 

template<Time Tm, int Len> 
struct constraint; 

//Rule for Day  
template<int Len> 
struct constraint<Day, Len> : rule<(Len>= 8)> 
{}; 

template<Time Tm, int Len> 
class Timer : constraint<Tm, Len> 
{ 
    //your code 
}; 

prueba:

int main() { 
     Timer<Day, 7> timer1; //error 
     Timer<Day, 8> timer2; //okay 
     return 0; 
} 

demostraciones en línea:


Del mismo modo, se pueden agregar reglas de Week y Month como:

//Rule for Week 
template<int Len> 
struct constraint<Week, Len> : rule<(Len>= 10)> 
{}; 

//Rule for Month 
template<int Len> 
struct constraint<Month, Len> : rule<(Len>= 100)> 
{}; 
7

Todas las otras respuestas van para metaprogramming para detectar la condición, lo haría por otra parte mantener las cosas simples:

template<Time t, int length> 
class Timer 
{ 
    static_assert((t == Day && length > 7) 
       ||(t == Week && length > 10) 
       ||(t == Month && length > 99), "Invalid parameters" 
}; 

El compilador activará la aserción si las condiciones no se cumplen, y es bastante simple de verificar por el mensaje de error y/o mirando la línea.

El uso de herramientas SFINAE desactivar versiones del tipo no también conseguir el mismo resultado: el código no se compilará, pero a costa de hacer que los mensajes de error más complejo para leer: ¿qué significa que Timer<Day,5> no es una ¿tipo? seguramente lo es, ¡es la instanciación de Timer<Time,int>!

EDIT: Lo anterior static_assert está implementado en C++ 0x, en los compiladores de C++ sin 0x se puede implementar como una macro static_assert:

#define static_assert(cond, name) typedef char sassert_##name[ (cond)? 1 : -1 ]; 

Este simple macro no acepta una cadena literal como segundo argumento, pero más bien una sola palabra. El uso sería:

static_assert(sizeof(int)==4, InvalidIntegerSize)) 

y mensajes de error se requiere un poco de análisis humana, como el compilador se quejará (si no se cumple la condición) que el tamaño de la sassert_InvalidIntegerSize es negativo.

+0

Debe mencionar que esta es la solución C++ 0x. El OP puede no saberlo. – Nawaz

+0

@Nawaz: Hay diferentes sabores de 'static_assert', algunos de los cuales son C++ 0x y otros no. La implementación más simple de 'static_assert' es' #define static_assert (cond, name) typedef char sassert _ ## name [(cond)? 1: -1]; ', pero por supuesto que no aceptaría un literal de cadena como segundo argumento, por lo que se usaría como:' static_assert (..., InvalidParameters) 'y el mensaje de error sería un poco peor, similar a 'size of array 'sassert_InvalidParameters' es negativo'. Actualmente estamos usando una macro similar a la de nuestro código base y el compilador no tiene soporte para C++ 0x. –

+0

Si toma este sabor, entonces el mensaje de error no es tan bueno como decía su publicación original. Ahora la metaprogramación de plantillas es tan buena qw esta solución, en términos de "mensaje de error útil". – Nawaz

0
enum Time { Day, Week, Month }; 
template<Time T> struct Length; 
template<> struct Length<Day> { static const int value = 8 ; }; 
template<> struct Length<Week> { static const int value = 9; }; 
template<> struct Length<Month> { static const int value = 10; }; 

template<bool b> struct Limit; 
template<> struct Limit<true> { typedef bool yes; }; 

#define COMPILE_ASSERT(V) typedef typename Limit<(V)>::yes checked 

template<Time t, int length> 
class Timer 
{ 
    COMPILE_ASSERT(length >= Length<t>::value); 
}; 

Ver demo here.

Cuestiones relacionadas