c++ - 如果表达式在编译时未知,则通过静态断言
问题描述
我想实现my_static_assert
与 c++17 单参数略有不同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是为了避免病理性零病例。
- 如果表达式是一个常量表达式,我们得到一个标准数组。否则我们会得到一个 VLA。
- 现在我们调用两个重载函数之一。重载决议总是最后选择 ac var-arg 函数。如果我们得到的是一个常规数组,则选择第一个已删除的重载,并且断言失败。
- 如果我们得到一个 VLA,则选择第二个重载并且断言通过。
我还没有彻底测试它,但它似乎适用于 Clang 和 GCC。现场观看。
@Artyer很乐意在godbolt上分享基于这种方法的解决方案。
这是该问题的代码简化:
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)
重载的使用相同,除了这次我们从调用中获取实际结果类型 via decltype
,并继续从中创建一个真正的编译时布尔常量。
这允许直接使用static_assert
,并且作为一个很好的功能,我们可以将字符串化的令牌汤传递给它,以获取表达式失败的错误指示。
推荐阅读
- vb.net - 尝试打开控件/表单的代码会弹出表单设计器代码
- python - 使用 Python Pycharm 在 Big Query 中查询公共数据集
- css - grid-row-gap 影响带有显示的 div:无
- javascript - 如何从 Apollo graphql 客户端状态中检索值
- php - 计数不可数对象 PHP 7.2
- javascript - 即使 map() 呈现的组件不是兄弟姐妹,是否可以避免在同一个数组上使用 .map() 两次?
- php - laravel 新项目 - 获取 /name 的索引而不是欢迎页面
- javascript - Javascript表单选择更改选项动态列表/一对多列表
- java - Maven 使用子 POM 中的子路径解析哪些 URL?
- r - 如何将 R 数据帧汇总到一个单元格中?