如何在 gdb/lldb 调试中打印模板成员函数返回的值

how to print value returned by template member function in gdb/lldb debugging

OpenCV的classcv::Mat中有一个名为at的模板成员函数:

//definition of at 
template<typename _Tp> inline const _Tp& Mat::at(int i0, int i1) const{
  // ...
}

//my codes
cv::Mat eyePts_left;
// ...
if(std::max(eyePts_left.at<float>(0,0),eyePts_left.at<float>(16,0)) > eyePts_left.at<float>(61,0)){ 
  //do something
}

我要打印表达式的值:

eyePts_left.at<float>(0,0)

在 lldb 调试会话中,但它抱怨:

(lldb) p eyePts_left.at<float>(0, 0)
error: warning: warning: got name from symbols: at
error: <user expression 21>:1:13: no member named 'at' in 'cv::Mat'
eyePts_left.at<float>(0, 0)
~~~~~~~~~~~ ^
error: <user expression 21>:1:21: expected '(' for function-style cast or type construction
eyePts_left.at<float>(0, 0)
               ~~~~~^

那么,检查这个与模板相关的表达式的值的正确方法是什么?

模板函数和模板化实体的当前调试信息通常很尴尬,因为它只描述实例化,而不是将模板描述为抽象实体,所以模板化函数只是显示在调试信息中,就像在某处带有尖括号的函数一样在名字中。这使得从调试信息到编译器表示变得棘手,lldb 可以将其输入到它的 clang 副本中,以便 clang 可以在表达式中正确解析它们。正如您所发现的,目前这不起作用。

但是,如果您真的需要这样做,您可以通过一些创造性的转换来解决这个问题,例如:

查找函数地址,例如

(lldb) image lookup -n Mat::at<float>
1 match found in /tmp/a.out:
        Address: a.out[0x0000000100003f30] (a.out.__TEXT.__text + 64)
        Summary: a.out`float const& Mat::at<float>(int, int) at template_fun.cpp:4

手动将呼叫投向该地址:

(lldb) expr ((float &(*) (Mat *, int, int))0x0000000100003f30)(&my_mat, 10, 20)
Called with 10 20
(float) [=11=] = 30

这不是你真正的功能,只是我做的一个玩具所以不要关注实际效果。

请注意,如果您最终经常这样做并且不是 100% 喜欢 C 函数转换语法,您可以在代码或 lldb 中为它创建一个 typedef,例如:

(lldb) expr typedef float &(*$Mat_at_type) (Mat *, int, int)

这简化了调用:

(lldb) expr (($Mat_at_type)0x0000000100003f30)(&my_mat, 10, 20)
Called with 10 20
(float)  = 30

然后,如果您最终经常这样做,您甚至可以这样做:

(lldb) command alias call_at expr -- (($Mat_at_type)0x0000000100003f30)
(lldb) call_at (&my_mat, 10, 20)