C++ 如何最好地防止自定义断言中没有sizeof的未使用变量警告?

C++ 如何最好地防止自定义断言中没有sizeof的未使用变量警告?,c++,c++11,lambda,assert,sizeof,C++,C++11,Lambda,Assert,Sizeof,根据中的建议,我已经使用自己的assert版本(称为emp_assert)有一段时间了。因此,设置NDEBUG时,我的断言如下所示: #define emp_assert(EXPR) ((void) sizeof(EXPR) ) 此定义确保EXPR中的任何变量在编译器中仍被视为“已使用”,但不会影响运行时性能 不幸的是,我最近发现在断言中使用lambdas都会产生编译错误,因为lambdas不能放入sizeof中 我的选择似乎是: 只需去除sizeof;我的代码中很少有不使用变量的情况,只能手

根据中的建议,我已经使用自己的assert版本(称为
emp_assert
)有一段时间了。因此,设置NDEBUG时,我的断言如下所示:

#define emp_assert(EXPR) ((void) sizeof(EXPR) )
此定义确保EXPR中的任何变量在编译器中仍被视为“已使用”,但不会影响运行时性能

不幸的是,我最近发现在断言中使用lambdas都会产生编译错误,因为lambdas不能放入sizeof中

我的选择似乎是:

  • 只需去除sizeof;我的代码中很少有不使用变量的情况,只能手动处理它们
  • 避免在资产中使用labdas
  • 想出一个替代sizeof的方法,也会有同样的效果
  • 选项1目前是我的首选,但我在许多项目中使用这个断言系统,在未来一段时间内可能会遇到问题

    选项2似乎太有限了,特别是因为我可以想象未来的意外互动

    选项3将是最优雅的临时解决方案,但我需要帮助来想出一个如何实现它的想法

    编辑:下面是一些示例代码来说明这个问题

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    #define NDEBUG
    
    // Relevant excerpt from "emp_assert.h"
    #ifdef NDEBUG
    #define emp_assert(EXPR) ((void) sizeof(EXPR))
    #else
    #define emp_assert(EXPR)                           \
      do { if ( !(EXPR) ) {                            \
          std::cerr << "Assert Error (In " << __FILE__ \
                    << " line " << __LINE__            \
                    << "): " << #EXPR << std::endl;    \
          abort(); }                                   \
      } while (0)
    #endif
    
    // Code to trigger the problem (asserting that all ints in a vector are less than 8.)
    int main()
    {
      std::vector<int> v = {1, 2, 3, 4, 8};
      emp_assert( std::all_of(v.begin(), v.end(), [](int i){return i < 8;}) );
    }
    
    #包括
    #包括
    #包括
    #定义NDEBUG
    //“emp_assert.h”的相关摘录
    #ifdef-NDEBUG
    #定义emp_assert(EXPR)((void)sizeof(EXPR))
    #否则
    #定义emp_断言(EXPR)\
    do{if(!(EXPR)){\
    
    我相信我找到了一个解决方案。由于lambda表达式不允许出现在未赋值的操作数中,但允许出现在常量表达式的未赋值部分,我们应该能够利用这一事实

    具体地说,我已经将我的#define when NDEBUG设置为:

    #define emp_assert(EXPR) {                             \
       constexpr bool __emp_assert_tmp = false && (EXPR);  \
       (void) __emp_assert_tmp;                            \
    }
    
    constepr
    确保在编译时对表达式的其余部分求值。但是
    false&&(EXPR)
    短路,因此永远不会对EXPR求值,但其中的变量不会被视为未使用

    变量
    \uuuu emp\u assert\u tmp
    是在它自己的作用域内创建的,因此多个断言不会冲突。高度特定的名称将确保我们不会意外地跟踪EXPR中使用的变量。任何合理的优化编译器都应该完全删除额外的变量,因此我认为它不会导致优化反倾销问题

    在我的测试中,EXPR中没有执行任何内容,lambda不会出错,而且似乎一切都正常工作


    如果您看到我缺少的任何问题,请告诉我。

    为什么使用
    sizeof
    ?在您的示例中,我看不到使用
    sizeof
    的任何目的,为什么不这样定义:

    #define emp_assert(exp) ((void) exp)
    
    如果要防止未使用的变量警告,可以使用c++17属性抑制未使用实体上的警告。例如:

    [[maybe_unused]]
    auto l = [](int i){return i < 8;};
    

    参见您的示例。

    emp_assert
    的要点是什么?它与
    assert
    static_assert
    有什么不同?两个主要区别:当我打开单元测试标志时,它报告错误而不中止(这样我就可以测试我的断言),以及当我使用Emscripten编译时(到asm.js)它使用Javascript警报来提供信息。您是否可以包含一些使用
    emp_assert
    的代码并显示问题?向委员会提交一个bug,要求他们删除未赋值操作数中对lambda的限制?@T.C.看起来您是对的;这是一个实际的限制,因此无法找到和替换solu另一方面,这里对这个问题进行了很好的讨论,可能通过使用常量表达式提供了一些可能性:这将使odr使用
    EXPR
    的子表达式,而不像
    sizeof
    。为什么
    定义emp\u assert(EXPR){(void)EXPR;}
    不够?sizeof()防止任何意外的副作用。如果assert具有更改任何变量的函数调用,则可能会影响结果,但如果它位于sizeof()中,则将确保调用不会实际发生。所有这些都表明,现在C++17解决了一个问题,C++20解决了另一个问题,这是正确的。
    static_assert(sizeof([](int i){return i < 8;}) == 1);