c++ - 为什么如果 constexpr 未能绕过 constexpr 评估?
问题描述
我正在为使用宏进行类型分派构建一个静态循环。这是我到目前为止所取得的成就。
#define LOOP(n, f) \
static_assert(n <= 8 && "static loop size should <= 8"); \
do { \
if constexpr (n >= 8) \
f(std::integral_constant<size_t, n - 8>()); \
if constexpr (n >= 7) \
f(std::integral_constant<size_t, n - 7>()); \
if constexpr (n >= 6) \
f(std::integral_constant<size_t, n - 6>()); \
if constexpr (n >= 5) \
f(std::integral_constant<size_t, n - 5>()); \
if constexpr (n >= 4) \
f(std::integral_constant<size_t, n - 4>()); \
if constexpr (n >= 3) \
f(std::integral_constant<size_t, n - 3>()); \
if constexpr (n >= 2) \
f(std::integral_constant<size_t, n - 2>()); \
if constexpr (n >= 1) \
f(std::integral_constant<size_t, n - 1>()); \
} while (0);
template <typename T> constexpr size_t tupleSize(T&) { return tuple_size_v<T>; }
int main() {
auto t = std::make_tuple(1, "string", 0.2, 3, 1, 1, 1);
LOOP(tupleSize(t), [&](auto i) { cout << std::get<i>(t) << endl; });
return 0;
}
和godbolt链接 https://godbolt.org/z/GcMZI3
问题是,为什么前四个分支编译失败?
解决方案
不要使用宏,而是使用函数模板。根据模板的当前实例化丢弃if constexpr
未采用的分支来工作。
template <std::size_t n, typename F>
void loop(F&& f)
{
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
用法:
int main() {
constexpr auto t = std::make_tuple(1, "string", 0.2, 3);
loop<tupleSize(t)>([&](auto i) { cout << std::get<i>(t) << endl; });
return 0;
}
如果 constexpr if 语句出现在模板化实体中,并且 if 条件在实例化后不依赖于值,则在实例化封闭模板时不会实例化丢弃的语句。
在模板之外,完全检查丢弃的语句。if constexpr 不能替代 #if 预处理指令
推荐阅读
- reactjs - 从 React 向 Spring REST 发送授权请求
- debian - Debian 发行版特定控制文件
- c# - 如何在运行时读取或捕获跟踪消息并使用 C# 将它们存储在字符串中?
- javascript - 命中 API 端点的 Angular 材料数据表
- database - Haskell 持久化 - 通过外键获取价值
- python - 尝试使用 sqlite3 插入多行数据(类型错误与编程错误)
- c - 在 C 中使用标记的函数编译错误
- django - 如何在表格中显示带有表格中对象标题的下拉列表?Django 模型窗体
- angular - 角度引导按钮单击功能
- ember.js - Ember Octane 如何获取要显示的错误消息?