调试模板实例化 [英] Debugging template instantiations

查看:142
本文介绍了调试模板实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用C ++模板进行元编程时,是否有一个方法可以使用,像调试器一样,逐步实例化和编译模板?看起来现在,当创建一个复杂的模板网络,真的没有一个很好的方式来调试它们,除了看看编译器错误消息,看看模板是如何实例化(如果有任何编译器错误)以及如果正在生成意外事件,则从错误消息向后工作的尝试。我不确定如果我正在寻找甚至存在,因为它必须是在编译时完成的东西,但基本上它将是一个方法,像一个步骤通过代码和检查堆栈帧 gdb 在运行时,可以停止编译器,并检查环境中的一个模板或一组嵌套模板被实例化的顺序。

When doing metaprogramming using C++ templates, is there a method that can be used, sort of like a debugger, to step through how the templates are being instantiated and complied? It seems right now, when creating a complicated network of templates, there really isn't a very good way of debugging them other than looking at the complier error messages to see how the templates are being instantiated (if there are any compiler errors), and the attempt to work backwards from the error messages if something unexpected is being generated. I'm not really sure if what I'm looking for even exists, as it would have to be something that is done at compile time, but basically it would be a method, sort of like stepping through code and examining the stack frame in gdb at runtime, where the compiler could be stopped and the environment examined for the sequence by which a template or set of nested templates is being instantiated.

例如,我创建了一些简单的代码,如下所示:

For instance, let's say I created some simple code like the following:

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_type float_return_type 正在被实例化,或实例化失败。

I know this is relatively easy code to follow, but templates can get quite a bit more involved, especially when doing metaprogramming, recursion, etc. I understand that the complier will issue error messages that can be used to deduce how templates are being instantiated, but I'm also wondering what can be done when the actual template code is correct in a syntactic sense, but the runtime results are still incorrect. It would be nice for instance to have a method to stop the compiler and see what test, as well as int_return_type and float_return_type, was being instantiated with, or what instantiations were failing.

现在是唯一可用的调试具有此级别粒度的模板1)当代码不正确时的编译器错误消息,以及2)反汇编器和调试器的组合,以查看如果运行时结果不正确则生成了哪些实例化代码。或者还有一些其他实用程序,帮助看模板如何实例化,并查看/检查编译器生成的代码调查和调试模板错误?

Are the only options available right now for debugging templates with this level of granularity 1) the compiler error messages when the code is incorrect, and 2) a combination of disassemblers and debuggers to see what instantiated code was generated if the run-time results are incorrect? Or are there some other utilities out there that help with "watching" how templates are instantiated, and see/inspect what code is generated by the compiler to investigate and debug template errors?

推荐答案

这些都是很基本的,但在大多数情况下他们都为我工作。

These are pretty basic, but they have worked for me in most cases. I'm interested to see what others have to say too.

对所设想的例子表示道歉。

Apologies for the contrived examples.

从小型沙箱开始,一旦模板代码开始表现异常或者您正在做复杂的事情,就开始测试。我对模板很舒服,我仍然这样做几乎立即。简单来说,它会更快地发现错误。

Starting with small sandboxes to test template code as soon as it starts behaving weird or you are doing something complicated. I am pretty comfortable with templates and I still do this almost immediately. Simply, it uncovers errors faster. You have done it for us here, so I presume that this is moot.

指定临时类型

临时人可以模糊不能满足您的意图。我看到很多代码,像下面这样。

Temporaries can obfuscate where your intentions are not met. I have seen a lot of code that does something like the below.

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

告诉编译器你期望的类型会更快失败,更好的消息处理。

Telling the compiler what type you expect will fail faster and potentially will give you a better message to deal with.

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

使用typeid

使用 typeid(T).name()在调试语句中打印模板名称。这将给你一个字符串,你可以使用它来看看编译器是如何实现类型。

Using typeid(T).name() to print template names in debug statements. This will give you a string that you can use to see how the compiler decided to fulfill the type.

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

避免不必要的默认实现

以这样的方式写入模板:有默认实现。

Write templates in such a way that they don't have default implementations.

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 工作,因为你不能为所有类型提供一个好的实现。如果在代码库的不同部分使用,编译器错误不会立即有用。

This enforces users of print_whole_number have their own my_traits specialization. They will get an compiler error instead of half working because you couldn't supply a good implementation for all types. The compiler error won't be immediately helpful if used in a disparate part of a code base, admittedly.

这篇关于调试模板实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆