编译时检查和运行时检查“同时”

Compile time check AND runtime check 'at the same time'

提问人:darune 提问时间:9/4/2019 最后编辑:darune 更新时间:9/4/2019 访问量:921

问:

假设我有以下简化程序:

godbolt.org 链接

#include <cassert>

struct Dimensions {

    Dimensions& operator=(int i) {
      assert(i != 0);
      return *this;
    }

};

int getDim();

int main() {
    Dimensions dims;
    dims = getDim();//ok, just use runtime assert
    dims = 0;//compile error wanted here
    return 0;
}

在第一种情况()中,无法检查编译时,因此我们很乐意在运行时检查它。getDim

但是,在理论上看起来是可能的时,是否有可能在编译时进行检测(对于第二种情况),?(也许甚至带有某种重载或包装器?dims = 0;

C++ C++17 编译时 静态断言

评论

4赞 walnut 9/4/2019
@george_ptr 将始终给出编译时错误,因为在该上下文的常量表达式中不可用。i
2赞 463035818_is_not_an_ai 9/4/2019
草率地说,在 是一个运行时值。只有当你能接受将其转换为编译时值时,你才能对它进行静态断言(例如,作为模板参数,正如 StackDanny 所建议的那样)dims = 0;0
1赞 darune 9/4/2019
@Bathsheba,这是一个好主意,但是我不能在实际情况下使用,而且它甚至不是尺寸(我只是认为这会更好地传达意思)
1赞 Bathsheba 9/4/2019
@darune:不确定我是否应该这样做——我认为这太特殊了,我不会自己做,而且我认为运行时断言已经足够好了。
2赞 KamilCuk 9/4/2019
想让它工作,但它的行为很奇怪,也许其他人能够修复它。std::is_constant_evaulated()

答:

8赞 KamilCuk 9/4/2019 #1

在 C 中使用 gcc 编译器的典型方法,也适用于 C++:使用内置函数检查表达式是否是持续计算的,然后检查表达式,然后调用用 或 声明的函数。这样:__builtin_constant_p__attribute__((__warning__))__attribute__((__error__))

#include <cassert>
#include <type_traits>

#define CONCAT(a, b) a ## b
#define XCONCAT(a, b) CONCAT(a, b)
#define maybe_static_maybe_not_assert(expr) do { \
    if (__builtin_constant_p(expr)) { \
            if (!(expr)) { \
                extern __attribute__((__warning__( \
                "static_assert: expression: " #expr " will fail on runtime!" \
                ))) void XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
              XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
         } \
    } \
    assert(expr); \
} while(0)

struct Dimensions {

    Dimensions& operator=(int i) {
        maybe_static_maybe_not_assert(i != 0);
        return *this;
    }

};

int getDim();

int main() {
    Dimensions dims;
    dims = getDim();
    dims = 0;
    dims = 1;
    return 0;
}

当使用优化进行编译时,它应该发出警告:

In member function 'Dimensions& Dimensions::operator=(int)',
    inlined from 'int main()' at <source>:32:12:
<source>:12:70: warning: call to 'maybe_static_maybe_not_assert_warn21' declared with attribute warning: static_assert: expression: i != 0 will fail on runtime! [-Wattribute-warning]
   12 |                 XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
      |                                                                      ^
<source>:21:9: note: in expansion of macro 'maybe_static_maybe_not_assert'
   21 |         maybe_static_maybe_not_assert(i != 0);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 0

这是在 glibc 中实现的方式。_FORTIFY_SOURCE

评论

0赞 darune 9/4/2019
msvc 也可以做到这一点吗?(或叮当声?
0赞 KamilCuk 9/4/2019
clang 支持 GNU 扩展,因此它应该与 clang 一起使用,但您必须更改为 .clang 不识别 和 属性,但具有通常使用的属性。__attribute__((__warning__))__attribute__((__deprecated__))warningerrordeprecated
0赞 darune 9/4/2019
我想这在 MSVC 上是不可能的吗?而且 MS 方面没有计划支持它(?
1赞 KamilCuk 9/4/2019
我没有使用 MSVC 的经验,所以我不愿意回答。我从未见过在 MSVC 中做的方法。__builtin_constant_p
1赞 Cyan 3/16/2021
@KamilCuk : 这将如何工作?似乎每当在源代码中调用该函数时,无论是否会调用该函数,都会触发警告,从而忽略了 DCE 优化。clang__attribute__((__deprecated__))