我正在尝试编写constexpr查找函数,该函数将返回包含特定值的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()
一起使用时如何失败?
我也找到了这个answer,但是用户从头开始构建数组类,而我不想这样做。
答案 0 :(得分:3)
似乎是编译器错误。 f1
和f2
都应该以相同的方式编译。
主要问题是,这是"name1" == "name1"
和"name1" != "name2"
的假设。该标准实际上不提供此类保证,请参见[lex.string]/16:
所有字符串文字是否都是不同的(即存储在不重叠的对象中),并且不确定string-literal的连续求值是产生相同对象还是不同对象。
即使最有可能成立该假设,也明确不允许比较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;
}