使用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;
}
Run Code Online (Sandbox Code Playgroud)
我知道这是相对容易遵循的代码,但模板可以更多地涉及,特别是在进行元编程,递归等时.我理解编译器会发出错误消息,可以用来推断模板的实例化方式,但我也想知道当语法意义上的实际模板代码是正确的时可以做些什么,但运行时结果仍然不正确.这将是很好的实例有一个方法来停止编译器,看看有什么test
,以及int_return_type
和float_return_type
,正在用实例化,或者是没有什么实例.
现在是唯一可用于调试具有此级别粒度的模板的选项1)代码不正确时的编译器错误消息,以及2)反汇编程序和调试器的组合,以查看运行时结果是否生成了实例化代码不正确的?或者是否有一些其他实用程序可以帮助"观察"模板的实例化,并查看/检查编译器生成的代码以调查和调试模板错误?
Tom*_*err 29
这些是非常基本的,但在大多数情况下它们对我有用.我很想知道其他人也要说些什么.
为人为的例子道歉.
使用沙箱
从小沙箱开始测试模板代码,一旦它开始表现得很奇怪,或者你正在做一些复杂的事情.我对模板很满意,而且我几乎立即就这样做了.简单地说,它可以更快地发现错误.你在这里为我们做过,所以我认为这没有实际意义.
指定临时类型
临时工可以模糊不符合你意图的地方.我已经看到很多代码可以执行类似下面的操作.
template<typename T>
T calc(const T &val) {
return some_other_calc(val) / 100.0;
}
Run Code Online (Sandbox Code Playgroud)
告诉编译器你期望的类型会更快地失败,并且可能会给你一个更好的消息来处理.
template<typename T>
T calc(const T &val) {
T val_ = some_other_calc(val);
return val_ / 100.0;
}
Run Code Online (Sandbox Code Playgroud)
使用typeid
使用typeid(T).name()
打印在调试报表模板名称.这将为您提供一个字符串,您可以使用该字符串来查看编译器如何决定实现该类型.
template<typename T>
typename void test() {
std::cout << "testing type " << typeid(T).name() << std::endl;
// ...
}
Run Code Online (Sandbox Code Playgroud)
避免不必要的默认实现
以这样的方式编写模板,使它们没有默认实现.
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;
}
Run Code Online (Sandbox Code Playgroud)
这强制用户print_whole_number
有自己的my_traits
专业化.它们将得到编译器错误而不是一半工作,因为您无法为所有类型提供良好的实现.如果在代码库的不同部分中使用,编译器错误将不会立即有用.
我喜欢使用优秀的基于 Web 的 Comeau 编译器进行调试。它可以注意到标准兼容性方面的错误,而其他编译器则无法...
Comeau 的一大优势是提供比 GCC 或 MSVC 更易读的错误消息。
static_assert
另外,请记住尽可能使用's - 即使您确定答案是正确的。