gpt4 book ai didi

c++ - 如果表达式在编译时未知则通过的静态断言

转载 作者:可可西里 更新时间:2023-11-01 15:22:15 25 4
gpt4 key购买 nike

我想实现与 c++17 单参数 static_assert 略有不同的 my_static_assert:如果 my_static_assert 中的条件 是在编译时未知,它应该通过

下例中的第二个 my_static_assert 应该通过,但如果我使用 static_assert 它将失败。

#include <iostream>

int x, y;
constexpr int f1() { return 0; }
constexpr int f2() { return 0; }
int f3() { return x; }
int f4() { return y; }
constexpr int sum(int a, int b) { return a + b; }

int main() {
std::cin >> x >> y;

// it should fail
my_static_assert(sum(sum(f1(), f2()), sum(f1(), f1())) != 0);

// it should pass
my_static_assert(sum(sum(f1(), f2()), sum(f4(), sum(f3(), f1()))) != 0);
}

如果你想知道为什么会出现这个问题:

我正在使用叶函数 f1、f2、f3、f4 和表达式节点上的操作构建表达式:sum、mul、div、sub。在编译时已知的叶子包含始终为 0 的值。

我正在尝试检查我的表达式是否包含至少一个在编译时未知的元素。

最佳答案

如果您愿意使用具有 GNU 扩展的编译器,那是有可能的。所以请注意。

它需要两个重载和一个辅助宏:

template<std::size_t N>
constexpr void assert_helpr(int(&)[N]) = delete;

void assert_helpr(...) {}

#define my_static_assert(...) do { \
__extension__ int _tmp [(__VA_ARGS__) + 1]; \
assert_helpr(_tmp); \
} while(0)

它的工作原理如下:

  1. 宏获取您的 token 汤并将其视为一个完整的表达式。 +1 是为了避免病态的零案例。
  2. 如果表达式是常量表达式,我们得到一个标准数组。否则我们会得到一个 VLA。
  3. 现在我们调用两个重载函数之一。重载决议总是最后选择一个 c var-arg 函数。如果我们得到的是一个常规数组,则选择第一个删除的重载,并且断言失败。
  4. 如果我们得到一个 VLA,则选择第二个重载并且断言通过。

我还没有彻底测试它,但它似乎在 Clang 和 GCC 上都有效。 See it live .


@Artyer非常友好地在 godbolt 上分享了基于这种方法的解决方案.

这是一个 reduction该问题的代码:

template<std::size_t N>
constexpr std::false_type assert_helpr(int(&)[N]);
constexpr std::true_type assert_helpr(...);

#define my_static_assert(...) do { \
__extension__ int _tmp[(__VA_ARGS__) + 1]; \
static_assert(decltype(assert_helpr(_tmp)){}, #__VA_ARGS__); \
} while(0)

同样使用重载,除了这次我们通过 decltype 从调用中获取一个实际的结果类型,然后继续从中创建一个真正的编译时 bool 常量。

这允许直接使用 static_assert,作为一个很好的功能,我们可以将字符串化的 token 汤传递给它,以在失败的表达式错误中得到指示。

关于c++ - 如果表达式在编译时未知则通过的静态断言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55936803/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com