为什么这个std :: string_view不是常量表达式?

4

我对于constexpr编程比较陌生,正在尝试在constexpr上下文中进行一些基本的string_view对象操作。在我的情况下,所有字符串最初都是源代码中的字面值,因此它们应该是常量表达式。我发现我可以从一个字符串字面量构造一个constexpr string_view而没有任何问题。

但是,如果我尝试调用带有字符串字面量的string_view参数的constexpr函数,那么编译会失败。请参见以下示例(Compiler Explorer链接):

#include <string_view>

// this doesn't compile; the compiler complains that `sv` is not a constant-expression
constexpr bool foo(std::string_view sv) 
{
    constexpr auto it = sv.find('b'); 
    return it != sv.end();
}

// this compiles just fine, though
constexpr std::string_view bar("def");

int main()
{
    foo("abc");
}

gcc 8.3 提供以下错误:

<source>: In function 'constexpr bool foo(std::string_view)':
<source>:5:32:   in 'constexpr' expansion of 'sv.std::basic_string_view<char>::find(((int)'b'), 0)'
<source>:5:36: error: 'sv' is not a constant expression
     constexpr auto it = sv.find('b');

为什么将 foo()string_view 参数不视为常量表达式?

3
在函数内部,其参数永远不会被视为constexpr。如果您将constexpr参数传递给它,则唯一可能成为constexpr的事情是返回值。 - HolyBlackCat
1
这里说的是 basic_string_view::findconstexpr 的。 - Nathan Pierson
1
您刚刚添加了过时的 constexpr https://godbolt.org/z/TKMxn8 - Marek R
只是为了澄清,当编译 foo 时无法评估 sv.find('b');,因为在编译 foo 时未知 sv 的值。另一方面,当调用 foo(bar); 时可以在编译时进行评估,因为在这种情况下,foo 的参数是已知的。 - Marek R
1
“使用constexpr做任何有用的事情都非常困难。”不,我指的是另外一件事。函数总是像参数不是constexpr一样工作,但如果它们实际上是constexpr,那么调用者可以在constexpr上下文中使用返回值。(假设该函数不执行任何无法在编译时完成的操作。) - HolyBlackCat
显示剩余4条评论
1个回答

5

constexpr 对象的值必须始终是编译时常量。由于函数 foo 无法控制传递给它的参数,参数 sv 不能被视为常量表达式(调用者可能传递非常量表达式参数),因此不能用于将 it 定义为 constexpr 对象。

it 的定义中可以简单地删除 constexpr 限定符,然后 foo 将会编译,甚至可以产生一个常数表达式(前提是参数是常数表达式)。 (常量表达式允许引用非-constexpr 对象,尽管不允许调用非-constexpr 函数。)

顺便说一下,在这里不应该使用名称 it,因为这是具有误导性的。 std::string_view::find 返回的是索引而不是迭代器。


这很有道理,只是感觉非常别扭。 这只是一个玩具示例,但我想能够在constexpr上下文中进一步使用find()的结果,例如 static_assert(ind> = 0)。为了使其编译,我需要将任何对constexpr的强制执行从函数体中取出,因此它需要在调用堆栈的更高位置进行处理,在那里我可以强制执行返回值为constexpr。有没有简化的方法?我希望将该逻辑实现在一个地方,而不是在调用不同文字量的函数的每个站点。 - Jason R
也许这些是 C++20 中的 consteval 能够解决的问题。 - Jason R
@JasonR 是的,我认为在这种情况下 consteval 是你想要的。在 C++17 中,我不认为有任何方法可以强制执行 std::string_view 参数的 constexpr 特性。你甚至不能将这样的参数提升为模板参数,因为它不满足成为模板参数类型的要求。 - Brian Bi
我在实践中还没有收集到使用constexpr函数的太多经验,但这听起来似乎存在一个可能性,即无法保证将参数传递给constexpr函数必须是可计算的,或者应该直接在“调用”处插入此类函数? - πάντα ῥεῖ
啊,抱歉。我刚才看到提到了“consteval”。 - πάντα ῥεῖ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接