2011-09-06 9 views
40

Al hacer metaprogramación con plantillas C++, ¿hay algún método que pueda usarse, algo así como un depurador, para ver cómo se crean y ejecutan las plantillas? Parece que ahora mismo, al crear una red complicada de plantillas, realmente no hay una forma muy buena de depurarlas aparte de mirar los mensajes de error del compilador para ver cómo se crean las instancias de las plantillas (si hay errores de compilación), y el intento de retroceder desde los mensajes de error si se genera algo inesperado. No estoy realmente seguro de si lo que estoy buscando existe, ya que tendría que ser algo que se hace en tiempo de compilación, pero básicamente sería un método, algo así como recorrer el código y examinar el marco de pila en gdb en tiempo de ejecución, donde se podría detener el compilador y examinar el entorno para ver la secuencia mediante la cual se crea una instancia de una plantilla o conjunto de plantillas anidadas.Instanciaciones de plantillas de depuración

Por ejemplo, digamos que he creado un código simple como la siguiente:

template<typename T, typename R = void> 
struct int_return_type {}; 

template<typename R> 
struct int_return_type<int, R> 
{ 
    typedef R type; 
}; 

template<typename T, typename R = void> 
struct float_return_type {}; 

template<typename R> 
struct float_return_type<float, R> 
{ 
    typedef R type; 
}; 

template<typename T> 
typename int_return_type<T>::type test() 
{ 
    cout << "T type is int" << endl; 
} 

template<typename T> 
typename float_return_type<T>::type test() 
{ 
    cout << "T type is float" << endl; 
} 

int main() 
{ 
    test<int>(); 
    test<float>(); 
    return 0; 
} 

Sé que esto es un código relativamente fácil de seguir, pero las plantillas pueden llegar a ser muy un poco más complicado, sobre todo cuando se hace metaprogramming, recursividad, etc. Entiendo que el compilador emitirá mensajes de error que se pueden usar para deducir cómo se crean instancias de las plantillas, pero también me pregunto qué se puede hacer cuando el código de la plantilla real es correcto en un sentido sintáctico, pero el tiempo de ejecución los resultados siguen siendo incorrectos Sería bueno, por ejemplo, tener un método para detener el compilador y ver qué test, así como int_return_type y float_return_type, estaban siendo instanciados, o qué instancias estaban fallando.

Son las únicas opciones disponibles ahora para depurar plantillas con este nivel de granularidad 1) los mensajes de error del compilador cuando el código es incorrecto, y 2) una combinación de desensambladores y depuradores para ver qué código instanciado se generó si la ejecución los resultados de tiempo son incorrectos? ¿O existen algunas otras utilidades que ayudan a "ver" cómo se crean instancias de las plantillas y a ver/inspeccionar qué código genera el compilador para investigar y depurar errores de plantilla?

+3

que no sea 'static_assert' para hacer cosas que quiere ver en los errores No creo que haya nada para ayudar – Flexo

Respuesta

26

Estos son bastante básicos, pero me han funcionado en la mayoría de los casos. Estoy interesado en ver lo que otros tienen que decir también.

Disculpas por los ejemplos artificiales.

Use cajas de arena

Comenzando con pequeñas cajas de arena en el código de plantilla de prueba tan pronto como comienza a comportarse raro o que está haciendo algo complicado. Me siento bastante cómodo con las plantillas y sigo haciendo esto casi de inmediato. Simplemente, descubre errores más rápido. Usted lo ha hecho por nosotros aquí, así que supongo que esto es discutible.

especificar tipos temporales

Temporaries puede ocultar cuando no se cumplan sus intenciones. He visto un montón de código que hace algo como lo siguiente.

template<typename T> 
    T calc(const T &val) { 
    return some_other_calc(val)/100.0; 
    } 

indica al compilador qué tipo esperas fallará más rápido y potencialmente le dará un mensaje mejor que tratar.

template<typename T> 
    T calc(const T &val) { 
    T val_ = some_other_calc(val); 
    return val_/100.0; 
    } 

Uso TypeId

Usando typeid(T).name() para imprimir nombres de plantilla de instrucciones de depuración. Esto le dará una cadena que puede usar para ver cómo el compilador decidió completar el tipo.

template<typename T> 
    typename void test() { 
    std::cout << "testing type " << typeid(T).name() << std::endl; 
    // ... 
    } 

Evita implementaciones por defecto innecesarios

plantillas escribir de una manera tal que no hacen tienen implementaciones por defecto.

template<typename T, bool is_integral = boost::is_numeric<T>::value > 
    struct my_traits; 

template<typename T> 
    struct my_traits<T, true> { 
    typedef uint32_t cast_type; 
    }; 

template<typename T> 
    void print_whole_number(T &val) { 
    std::cout << static_cast<my_traits<T>::cast_type>(val) << std::endl; 
    } 

Esto hace cumplir los usuarios de print_whole_number tienen su propio my_traits especialización. Obtendrán un error de compilación en lugar de medio en funcionamiento porque no podría proporcionar una buena implementación para todos los tipos. El error del compilador no será de ayuda inmediata si se usa en una parte dispar de una base de código, en verdad.

+9

+1 * Escribir plantillas de forma tal que no tengan implementaciones predeterminadas * – Manu343726

3

Me encanta usar el excelente compilador Comeau basado en web para la depuración. Puede notar errores en términos de compilación estándar donde los otros compiladores no pueden ...

Comeau tiene la gran ventaja de proporcionar mensajes de error mucho más legibles que GCC o MSVC.

Además, recuerde utilizar static_assert en todas partes donde sea posible, incluso si está seguro de que la respuesta es cierta.

+0

Por cierto, sé que esto es un poco fuera de tema, pero tengo curiosidad, mi código de muestra parece estar [compilando muy bien] (http://ideone.com/zcLmt), o no lo habría publicado (no hay nada como publicar código que no se compilará) ... qué configuraciones en el compilador Comeau era usted ¿utilizando? – Jason

+0

@Jason, modo estricto con extensiones C++ 0x. –

+0

@Jason, oh estúpido, no pegué todo el código ^^ –

Cuestiones relacionadas