【问题标题】:How to make the `static_assert` print the value it got on failure?如何让`static_assert`打印失败时的值?
【发布时间】:2019-12-24 21:55:58
【问题描述】:

运行这个:

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

template< int PathLength >
constexpr const int startfindlastslash(const char (&path)[PathLength]) {
    return PathLength;
}

int main(int argc, char const *argv[])
{
    STATIC_ASSERT( startfindlastslash( "cppdebugger/test_debugger.cpp" ) == 11 );
}

你得到了:

  1. g++ -o main.exe --std=c++14 test_debugger.cpp

    test_debugger.cpp: In function ‘int main(int, const char**)’:
    test_debugger.cpp:1:28: error: static assertion failed: startfindlastslash( "cppdebugger/test_debugger.cpp" ) == 11
     #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
                                ^
    test_debugger.cpp:10:5: note: in expansion of macro ‘STATIC_ASSERT’
         STATIC_ASSERT( startfindlastslash( "cppdebugger/test_debugger.cpp" ) == 11 );
         ^~~~~~~~~~~~~
    
  2. clang++ -Xclang -ast-print -fsyntax-only --std=c++14 test_debugger.cpp &gt; main.exe

    test_debugger.cpp:10:5: error: static_assert failed due to requirement 'startfindlastslash("cppdebugger/test_debugger.cpp") == 11' "startfindlastslash(
          \"cppdebugger/test_debugger.cpp\" ) == 11"
        STATIC_ASSERT( startfindlastslash( "cppdebugger/test_debugger.cpp" ) == 11 );
        ^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    test_debugger.cpp:1:28: note: expanded from macro 'STATIC_ASSERT'
    #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
                               ^             ~~~~~~~~~~~
    1 error generated.
    

编译器不会告诉它应该得到哪个值,它只是说这个值不相等。

【问题讨论】:

  • 我知道它在我的示例中打印的值是固定的,因为我使用了通用宏。但不知何故可以修复这个宏以显示实际值?
  • 我认为static_assert 不可能。您可以定义一个使用template &lt;int c&gt; struct V {}; 的宏并尝试复制该结构,如果c 值不匹配,它将生成编译时错误(例如无法从V&lt;30&gt; 转换为@987654330 @)。宏需要 2 个参数:预期值和实际值,由于它依赖于编译器诊断,结果可能因编译器而异。
  • @Phil1970,这似乎是个好主意!你能写一个答案吗? (很遗憾他们设计了标准 static_assert 有这个问题)
  • 我可能在 15 年前写了这样的代码,然后 static_assert 被添加到语言中。我不记得确切的实现。在实践中,static_assert 工作得很好,如果您在猜测该值时遇到问题,您始终可以通过打印实际值来调试应用程序。或者使用通常会给出实际值和预期值的单元测试框架。

标签: c++ templates c++14 c++17 static-assert


【解决方案1】:

我经常发现将static_asserts 包装在函数模板中很有用。然后编译器将至少打印错误消息中的函数模板参数。如果将此策略与@Phil1970 的值模板方法结合使用,您将获得相当不错的结果。

使用 GCC 编译时,以下 sn-p 会打印包含您的值的错误消息:In instantiation of 'constexpr void assert_equal(const_val&lt;T, A&gt;, const_val&lt;U, B&gt;) [with T = int; T A = 30; U = int; U B = 11]'

Clang 更好:&lt;source&gt;:13:5: error: static_assert failed due to requirement '30 == 11' "Values are not equal!"

#define MAKE_CONST(x) const_val<decltype(x), x>{}
#define STATIC_ASSERT_EQUAL(x, y) assert_equal(MAKE_CONST(x), MAKE_CONST(y));

template<typename T, T val>
struct const_val {
    constexpr const_val() = default;
    constexpr const_val(T v) {}
};

template<typename T, T A, typename U, U B>
constexpr void assert_equal(const_val<T, A>, const_val<U, B>) {
    static_assert(A == B, "Values are not equal!");
}

template< int PathLength >
constexpr const int startfindlastslash(const char (&path)[PathLength]) {
    return PathLength;
}

int main(int argc, char const *argv[])
{
  STATIC_ASSERT_EQUAL(startfindlastslash( "cppdebugger/test_debugger.cpp" ), 11);
}

这与您使用的语法不完全一样,为了方便起见,它涉及一个额外的宏,但希望它足以满足您的目的......

直播代码here.

【讨论】:

    【解决方案2】:

    [这并不是对“如何使 static_assert 打印值”的真正答案,而是对 OP 为何得到他的行为的解释。 ]

    Pre-c++17,static_assert 有两个参数。

    第一个是要计算的表达式,第二个是表达式不计算为真时要打印的消息。

    当您定义 STATIC_ASSERT 宏时,您将向 static_assert 提供您想要打印的消息 - 它正在为您打印该消息。

    【讨论】:

      猜你喜欢
      • 2021-05-07
      • 2018-04-26
      • 2012-12-23
      • 2013-07-14
      • 1970-01-01
      • 2010-10-02
      • 1970-01-01
      • 2014-07-01
      • 2016-04-24
      相关资源
      最近更新 更多