【问题标题】:How to effectively debug constexpr functions?如何有效地调试 constexpr 函数?
【发布时间】:2014-01-24 20:31:46
【问题描述】:

在 C++14 中,我们得到 upgraded version of constexpr,这意味着现在可以使用循环、if 语句和开关。 递归在 C++11 中已经成为可能。

我知道constexpr 函数/代码应该很简单,但问题仍然存在:如何有效地调试它?

即使在“The C++ Programming Language, 4th Edition”中也有一句话说调试很困难。

【问题讨论】:

  • 调试模板元程序的方式相同 :-)
  • 另请注意,constexpr 函数必须进行静态评估。如果你提供一个非 constexpr 参数,你就只有一个正常的函数调用,你应该能够调试它。
  • 我不明白问题是什么......
  • @Mehrdad:您应该能够在constexpr 函数上放置一个断点来中断编译器:)
  • 我们必须有一个g++ --gdb 选项。

标签: c++ debugging c++11 constexpr c++14


【解决方案1】:

如果通过调试你的意思是“让它知道某个表达式不是所需的值”,你可以在运行时检查它

#include <stdexcept>
#include <iostream>

constexpr int test(int x){ return x> 0 ? x : (throw std::domain_error("wtf")); }

int main()
{
  test(42);
  std::cout<< "42\n";
  test(-1);
  std::cout<< "-1\n";
}

【讨论】:

    【解决方案2】:

    调试constexpr函数有两个重要方面。

    1) 确保他们计算出正确的结果

    在这里,您可以使用常规的单元测试、断言或运行时调试器来单步调试您的代码。与测试常规函数相比,这里没有什么新东西。

    2) 确保它们可以在编译时进行评估

    这可以通过将函数评估为constexpr 变量赋值的右侧来测试。

    constexpr auto my_var = my_fun(my_arg);
    

    为了使其工作,my_fun 可以 a) 仅将编译时常量表达式作为实际参数。 IE。 my_arg 是文字(内置或用户定义)或先前计算的 constexpr 变量或模板参数等,并且 b)它只能在其实现中调用 constexpr 函数(因此没有虚拟,没有 lambda 表达式等)。

    注意:在您的constexpr 函数的编译时评估期间,实际上很难调试编译器的代码生成实现。您必须将调试器附加到编译器,并且实际上能够解释代码路径。也许未来的 Clang 版本会让你这样做,但在当前技术下这是不可行的。

    幸运的是,因为您可以解耦 constexpr 函数的运行时和编译时行为,调试它们并不像调试模板元程序(只能在编译时运行)那样困难。

    【讨论】:

    • 太棒了!所以基本上你可以在运行时使用“正常”调试,然后只确保它在编译时得到正确计算。我希望 constexpr 将使元编程更容易。我认为这是 C++1y 的一个很棒的特性
    • @fen 是的,我就是这样做的。而且它比模板元编程容易得多。例如,constexprswitch-statement 等效于 TMP 中的几个类模板特化。它大大减少了必须维护的代码行数,并且您始终可以选择使用运行时参数运行相同的代码。
    • 我在这里找到了一篇很棒的文章:cpptruths.blogspot.com/2011/07/… 它描述了 constexpr 如何让生活变得更简单。
    • 为此我是static_assert 的粉丝。它检查值 并且 要求在编译时计算它。示例:static_assert(my_fun(my_arg)==42", "my_fun(my_arg) failure")
    • @MarshallClow static_assert 的缺点是它只能在编译时工作,而@fen 链接中的 throw 技巧也可以在运行时工作
    【解决方案3】:

    我在 2015 年 4 月 3 日写的答案显然是错误的。我不明白我在想什么。

    这是“真正的”答案——我现在使用的方法。

    a) 像往常一样编写 constexpr 函数。到目前为止它不起作用。

    b) 当函数在编译时被调用时 - 编译失败,只显示一条消息,表示“无效的 constexpr”函数。这使得很难知道问题到底是什么。

    c) 制作小型测试程序,该程序使用仅在运行时知道的参数调用函数。使用调试器运行您的测试程序。您会发现您可以以正常方式跟踪该函数。

    我花了很长时间才弄清楚这一点。

    【讨论】:

    • 那你为什么不删除之前的答案呢?
    【解决方案4】:

    如果你用的是gcc,可以试试this

    还有一个关于它的introduce

    【讨论】:

      猜你喜欢
      • 2017-03-29
      • 2013-12-24
      • 2018-03-21
      • 2021-12-31
      • 2018-07-10
      • 2018-06-10
      • 2017-03-28
      • 1970-01-01
      • 2018-06-23
      相关资源
      最近更新 更多