【问题标题】:Implement assert without preprocessor in C++20在 C++20 中实现无需预处理器的断言
【发布时间】:2020-11-16 21:54:08
【问题描述】:

C++ 知道 assert(),它允许运行时检查编译为依赖于 NDEBUG 的任何内容。

我想使用编译器代码替换该宏并避免使用预处理器。我需要执行以下操作:

  • 如果表达式计算结果为false,则中断或终止
  • 记录调用断言的代码行
  • 放弃NDEBUG 构建的检查和传递的表达式

中断/终止应用程序很容易。

在 C++20 中有 std::experimental::source_location,我可以使用它来获取断言的代码位置。

可以使用requires 或constexpr if 完成编译时条件

但是我不知道如何避免表达式的评估。当将myAssert(expression) 实现为函数时,我需要将表达式结果作为函数参数传递,这意味着它无论如何都会被计算,即使该参数没有在函数内部使用。

有没有办法在 C++20 中解决这个问题?

编辑:模板示例:

template <typename T> requires (gDebug)
void assertTrue(const T& pResult, const std::experimental::source_location& pLocation) noexcept
{
   if (!static_cast<bool>(pResult))
   {
      // error handling
   }
}

template <typename T> requires (!gDebug)
void assertTrue(const T&) noexcept
{
}

【问题讨论】:

  • 这是为数不多的宏工作之一。您应该使用适合工作的工具。另外,assert 是运行时的东西,if constexpr 需要编译时间。
  • @NathanOliver 我相信if constexpr 的条件应该用作启用/禁用断言本身的(编译时)开关。
  • assert 或预处理器是否以某种方式冒犯了您?几十年来,它们一直为我们其他人工作得很好。
  • @Silicomancer "commas in expression" 好吧,这只是标准assert 的问题。您可以使用... 和__VA_ARGS__ 编写自己的。
  • 没有任何东西可以依赖于NDEBUG而不依赖于预处理器,因为NDEBUG是一个预处理器宏。

标签: c++ preprocessor assertion c++20


【解决方案1】:

我想您是在谈论禁用调试并且希望该功能成为 noop 的情况。我看到 2 个选项:

您可以使用宏。宏可能会被滥用,但它们有自己的位置,并且“传递表达式”而不评估它是宏的一种情况。

或者,传递一个可调用的对象,该可调用对象返回您要为其断言的结果。只在gDebug == True时调用:

template <typename F> requires (gDebug)
void assertTrue(const F& f, const std::experimental::source_location& pLocation) noexcept
{
   if (!static_cast<bool>(f()))
   {
      // error handling
   }
}

虽然这会使调用变得相当冗长。例如一个总是失败的:

assertTrue( [](){ return false; });

【讨论】:

  • 请注意,您的宏仅适用于 gDebug 是依赖值的模板函数。否则该语句不会被丢弃。
  • @NathanOliver 不完全理解。你是说if constexpr (false) foo();不会被丢弃?
  • 是的。 if constexpr 仅适用于模板代码。见:stackoverflow.com/questions/59393908/…
  • @NathanOliver 谢谢,决定简单地从答案中删除宏
猜你喜欢
  • 1970-01-01
  • 2012-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多