调试模板实例化

时间:2011-09-06 20:42:28

标签: c++ c++11

使用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被实例化,或者实例化失败了。< / p>

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

4 个答案:

答案 0 :(得分:29)

这些非常基本,但在大多数情况下它们对我有用。我很想知道其他人也要说些什么。

为人为的例子道歉。

使用沙箱

从小沙箱开始测试模板代码,只要它开始表现得很奇怪,或者你正在做一些复杂的事情。我对模板很满意,而且我几乎立即就这样做了。简单地说,它可以更快地发现错误。你在这里为我们做过,所以我认为这没有实际意义。

指定临时类型

临时工可以模糊不符合你意图的地方。我见过很多类似下面的代码。

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专业化。它们将得到编译器错误而不是 half 工作,因为您无法为所有类型提供良好的实现。如果在代码库的不同部分中使用,编译器错误将不会立即有用。

答案 1 :(得分:7)

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

答案 2 :(得分:3)

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

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

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

答案 3 :(得分:0)

2018年,我们有cppinsights.io。不确定是否对真正复杂的模板有用。