调试模板实例化

问题描述:

使用C++模板进行元编程时,是否有一种方法可以像调试器那样使用,以便逐步了解如何实例化和编译模板?现在看来,在创建一个复杂的模板网络时,除了查看编译器错误消息以查看如何实例化模板(如果存在任何编译器错误),实际上并没有很好的调试方法,并尝试从错误消息中反向工作,如果出现意想不到的情况。我不确定是否存在我正在寻找的东西,因为它必须是在编译时完成的东西,但基本上它会是一种方法,有点像遍历代码并检查堆栈框架gdb在运行时,其中可以停止编译器,并且环境检查模板或嵌套模板集实例化的顺序。调试模板实例化

举例来说,假设我创建了一些简单的代码如下所示:

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

我知道这是比较容易的代码跟随,但这样做的元编程时,模板可以更多地参与了不少,尤其是,递归等等。我知道编译器会发出错误消息,可以用来推断如何实例化模板,但是我也想知道当实际模板代码在句法意义上是正确的时候可以做什么,但是运行时结果仍然不正确。例如,有一种方法可以停止编译器,并查看test以及int_return_typefloat_return_type正在被实例化或哪些实例失败。

是目前唯一可用于调试具有此粒度级别的模板的代码1)代码不正确时的编译器错误消息,以及2)反汇编程序和调试程序的组合以查看运行时生成的实例化代码时间结果不正确?还是有其他一些实用工具可以帮助“观察”模板的实例化,并查看/检查编译器生成什么代码来调查和调试模板错误?

+3

除'static_assert'以外,你想要观察错误的东西我不认为有什么可以帮助 – Flexo

这些都很基本,但在大多数情况下它们都适用于我。我很想看看别人也有什么要说的。

道歉的人为的例子。

使用沙箱

尽快与小沙箱测试模板代码开始,因为它开始行为怪异,或者你正在做的事情复杂化。我对模板非常舒服,而且我几乎立即做到了这一点。简而言之,它可以更快地发现错误。你已经在这里为我们完成了,所以我认为这是没有意义的。

指定临时类型

临时变量可以混淆您的意图没有得到满足。我已经看到了很多类似于下面的代码。

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

告诉你期望什么类型将失败更快,而且可能会给你一个更好的消息来处理编译器。

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

使用TYPEID

使用typeid(T).name()打印在调试报表模板名称。这会给你一个字符串,你可以用它来看看编译器是如何决定实现这种类型的。

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

避免不必要的默认实现

写模板以这样的方式,他们有默认的实现。

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

这种强制的print_whole_number用户都有自己my_traits专业化。他们将得到一个编译器错误,而不是一半的工作,因为你无法为所有类型提供良好的实现。诚然,如果在代码库的不同部分中使用编译器错误,将不会立即有所帮助。

+9

+1 *以不具有默认实现的方式编写模板* – Manu343726

我喜欢使用优秀的基于Web的Comeau编译器进行调试。它可以注意到在其他编译器不能执行的标准汇编方面的错误...

Comeau具有比GCC或MSVC提供更多可读错误消息的巨大优势。

另外,请记住尽可能在任何地方使用static_assert - 即使您确定答案是正确的。

+0

顺便说一句,我知道这是一个小题外话,但我很好奇,我的代码示例似乎是[编译就好](http://ideone.com/zcLmt),或者我不会发布它(没有什么比发布代码不会编译)...... Comeau编译器中的什么设置是你的使用? – Jason

+0

@Jason,使用C++ 0x扩展的严格模式。 –

+0

@Jason,哦,我愚蠢,没有粘贴整个代码^^ –

是的,有一个模板元编程调试器。 Templight