2010-10-07 11 views
6

I tienen una siguiente plantilla struct:¿Cómo valido los parámetros de la plantilla en tiempo de compilación cuando una clase con plantilla no contiene funciones de miembros utilizables?

template<int Degree> 
struct CPowerOfTen { 
enum { Value = 10 * CPowerOfTen<Degree - 1>::Value }; 
}; 

template<> 
struct CPowerOfTen<0> { 
    enum { Value = 1 }; 
}; 

que se va a utilizar como esto:

const int NumberOfDecimalDigits = 5; 
const int MaxRepresentableValue = CPowerOfTen<NumberOfDecimalDigits>::Value - 1; 
// now can use both constants safely - they're surely in sync 

ahora que la plantilla requiere Degree ser no negativo. Me gustaría aplicar una afirmación en tiempo de compilación para eso.

Cómo lo hago? He intentado añadir un destructor a CPowerOfTen:

~CPowerOfTen() { 
    compileTimeAssert(Degree >= 0); 
} 

pero ya que no se llama directamente Visual C++ 9 decide no crear una instancia de ella y por lo que la sentencia assert en tiempo de compilación no se evalúa en absoluto.

¿Cómo podría cumplir una comprobación en tiempo de compilación para Degree ser no negativo?

Respuesta

8
template<bool> struct StaticCheck; 
template<> struct StaticCheck<true> {}; 

template<int Degree> 
struct CPowerOfTen : StaticCheck<(Degree > 0)> { 
    enum { Value = 10 * CPowerOfTen<Degree - 1>::Value }; 
}; 

template<> 
struct CPowerOfTen<0> { 
    enum { Value = 1 }; 
}; 

Editar: sin recursividad infinita.

// Help struct 
template<bool, int> struct CPowerOfTenHelp; 

// positive case  
template<int Degree> 
struct CPowerOfTenHelp<true, Degree> { 
    enum { Value = 10 * CPowerOfTenHelp<true, Degree - 1>::Value }; 
}; 

template<> 
struct CPowerOfTenHelp<true, 0> { 
    enum { Value = 1 }; 
}; 

// negative case 
template<int Degree> 
struct CPowerOfTenHelp<false, Degree> {} 

// Main struct 
template<int Degree> 
struct CPowerOfTen : CPowerOfTenHelp<(Degree >= 0), Degree> {}; 
+0

No se detuvo la recursividad en tiempo de compilación es un gran problema, sin embargo? – visitor

5

Puede utilizar un uint. No obtendrá un error de tiempo de compilación, pero al menos será autodocumentado.

+0

Exactamente. Los números no negativos son solo una falla. ¿Qué pasa con CPowerOfTen <10000>? Esto no debería funcionar de todos modos. – harper

+1

NUNCA use uint para forzar que un valor sea no negativo. En este caso, debe ser -1 pasado, se convierte en un valor gigantesco y pasa como un parámetro de plantilla, el compilador se colgará, y usted no sabrá qué hacer. Afortunadamente, la próxima C++ 0x ofrece afirman estático con un mensaje personalizado para informar en caso de error de aserción –

5

Puede utilizar BOOST_STATIC_ASSERT macro. O implemente la suya propia, la forma más simple de forzar una falla es realizar un typedef de una matriz de N elementos, donde N es positivo/negativo según el argumento.

El problema con este enfoque es que se producirá un fallo, pero se intentará realizar la recursividad no obstante. Eche un vistazo a boost::enable_if_c para usar SFINAE y fallar al crear una instancia de la plantilla si el argumento es negativo.

1

¿Qué hay de la implementación de un STATIC_CHECK macro?

template<bool> struct CompileTimeError; 
template<> struct CompileTimeError<true> {}; //specialized only for true 

#define STATIC_CHECK(expr) (CompileTimeError<(expr) != 0>()) 

Dentro main()

const int NumberOfDecimalDigits = -1; 
STATIC_CHECK(NumberOfDecimalDigits > 0); // Error : invalid use of incomplete type struct CompileTimeError<false> 

const int MaxRepresentableValue = CPowerOfTen<NumberOfDecimalDigits>::Value - 1; 
+0

El inconveniente de esta solución es que el cheque está separado de la 'struct'. – sharptooth

2

Puede reenviar la implementación de una clase también aceptar un parámetro booleano que indica si el resultado puede ser calculado.

#include <limits> 
template <int Degree, bool InRange> 
struct PowerOfTenImpl 
{ 
    enum {Value = 10 * PowerOfTenImpl<Degree - 1, InRange>::Value}; 
}; 

template <> 
struct PowerOfTenImpl<0, true> 
{ 
    enum {Value = 1}; 
}; 

template <int Degree> 
struct PowerOfTenImpl<Degree, false> 
{ 
}; 

template<int Degree> 
struct CPowerOfTen { 
    enum { Value = PowerOfTenImpl<Degree, Degree >= 0 && 
     Degree <= std::numeric_limits<int>::digits10>::Value }; 
}; 

int main() 
{ 
    const int a = CPowerOfTen<4>::Value; 
    const int b = CPowerOfTen<1000>::Value; 
    const int c = CPowerOfTen<-4>::Value; 
} 
Cuestiones relacionadas