c++ - Consexpr 使用 c++17 查找数组
问题描述
我正在尝试编写一个 constexpr find 函数,该函数将返回包含某个值的 std::array 的索引。下面的函数似乎可以正常工作,除非包含的类型是const char*
:
#include <array>
constexpr auto name1() {
return "name1";
}
constexpr auto name2() {
return "name2";
}
template <class X, class V>
constexpr auto find(X& x, V key) {
std::size_t i = 0;
while(i < x.size()) {
if(x[i] == key) return i;
++i;
}
return i;
}
int main() {
constexpr std::array<const char*, 2> x{{name1(), name2()}};
constexpr auto f1 = find(x, name1()); // this compiles
constexpr auto f2 = find(x, name2()); // this doesn't...
}
奇怪的是find(x, name1())
编译干净但find(x, name2())
失败并出现错误:
subexpression not valid in a constant expression
if(x[i] == key) return i; `
这个表达式在使用时如何工作,name1()
但在使用时失败name2()
?
我也找到了这个答案,但是用户从头开始构建数组类,我不想这样做。
解决方案
似乎是一个编译器错误。两者都f1
应该f2
无法以相同的方式编译。
主要问题是它是一个假设"name1" == "name1"
和"name1" != "name2"
。该标准实际上没有提供这样的保证,请参阅[lex.string]/16:
是否所有字符串文字都是不同的(即,存储在不重叠的对象中)以及字符串文字的连续评估是否产生相同或不同的对象是未指定的。
即使假设最有可能成立,但constexpr
明确不允许比较内部未指定的值,请参阅[expr.const]/2.23:
— 结果未指定的关系 ( [expr.rel] ) 或相等 ( [expr.eq] ) 运算符;
一种解决方法(也是正确的做法)是不依赖字符串文字的地址,而是比较实际的字符串。例如:
constexpr bool equals(const char* a, const char* b) {
for (std::size_t i = 0; ; ++i) {
if (a[i] != b[i]) return false;
if (a[i] == 0) break;
}
return true;
}
template <class X, class V>
constexpr auto find(X& x, V key) {
std::size_t i = 0;
while(i < x.size()) {
if(equals(x[i], key)) return i;
++i;
}
return i;
}
推荐阅读
- java - 为什么我需要 Servlet 的映射或注释,而不是 JSP?
- python - 需要帮助在 python 输出后添加文本
- sql - 在 SQL 中使用 Json auto 进入打开的 Json
- php - 如何将 HTML 登录页面连接到 myphpadmin 并根据数据库上的凭据将两个帐户定向到 2 个单独的登录页面
- python - 用python矩阵的特征向量和特征值
- r - 如何对 R 中的行和列进行子集化
- node.js - Windows 10下的nmp install -g,不识别为命令
- sqlalchemy - Fastapi sqlalchemy pydantic 关系字段
- html - 我错过了什么?CSS中的字体颜色
- node.js - 从所有获取公会 ID 的服务器更改昵称