lin*_*ver 4 c++ arrays constexpr 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...
}
Run Code Online (Sandbox Code Playgroud)
奇怪的是find(x, name1())编译干净但find(x, name2())失败并出现错误:
subexpression not valid in a constant expression
if(x[i] == key) return i; `
Run Code Online (Sandbox Code Playgroud)
这个表达式如何在使用 withname1()时工作但在使用 with 时失败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;
}
Run Code Online (Sandbox Code Playgroud)