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

Posted

技术标签:

【中文标题】为啥这个 std::string_view 不是常量表达式?【英文标题】:Why isn't this std::string_view a constant expression?为什么这个 std::string_view 不是常量表达式? 【发布时间】:2020-12-07 17:15:12 【问题描述】:

我对@9​​87654324@ 编程比较陌生,我正在尝试在constexpr 上下文中对string_view 对象进行一些基本操作。在我的例子中,所有字符串在我的源代码中都是以文字开头的,所以看起来它们应该是常量表达式。我发现我可以毫无问题地从字符串文字构造 constexpr string_view

但是,如果我尝试调用带有字符串文字的 string_view 参数的 constexpr 函数,那么编译将失败。请参阅以下示例 (Compiler Explorer link):

#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 参数不被视为常量表达式?

【问题讨论】:

供参考:en.cppreference.com/w/cpp/string/basic_string_view/find 在函数内部,它的参数永远不会被认为是 constexpr。如果您将 constexpr 参数传递给它,则唯一可能成为 constexpr 的就是返回值。 不过,basic_string_view::findconstexpr 你刚刚添加了废弃的constexprgodbolt.org/z/TKMxn8 “用 constexpr 做任何有用的事情都很难” 不,我的意思是别的。函数总是像参数不是 constexpr 一样工作,但如果它们实际上是 constexpr,那么 调用者 可以在 constexpr 上下文中使用返回值。 (假设函数不做任何在编译时不能做的事情。) 【参考方案1】:

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

constexpr 说明符可以简单地从it 的定义中删除,然后foo 将编译,甚至可以产生一个常量表达式(假设参数是一个常量表达式)。 (常量表达式允许引用非constexpr 对象,但不允许调用非constexpr 函数。)

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

【讨论】:

有道理,就是感觉很别扭。这是一个玩具示例,但我希望能够在constexpr 上下文中进一步使用find() 的结果,例如static_assert(ind &gt;= 0)。为了使它编译,我需要从函数体中强制执行constexpr,因此它需要在调用堆栈的更高层执行,我可以强制返回值为constexpr。有什么办法可以简化吗?我宁愿在一个地方实现该逻辑,而不是在我用不同文字调用函数的每个站点。 也许这些是 C++20 的consteval 解决的问题。 @JasonR 是的,我认为consteval 是您在这种情况下想要的。在 C++17 中,我认为没有任何方法可以强制执行 std::string_view 参数的 constexprness。您甚至不能将这样的参数提升为模板参数,因为它不满足成为模板参数类型的要求。 我在实践中使用 constexpr 函数的经验还不够多,但这听起来可能无法保证 constexpr 函数的参数必须可以从另一个 @987654343 计算@函数,还是应该直接在“调用”处插入这样的函数? 啊,对不起。我只看到提到了consteval

以上是关于为啥这个 std::string_view 不是常量表达式?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::string_view 比 const char* 快?

为啥 C++ 标准中没有 std::string_view 类型的参数的 std::basic_string 类的构造函数[重复]

将函数参数 `const char*` 转换为 `std::string_view` 是不是安全?

std::string_view 编译时散列

删除 std::string_view 的最后一个字符

带有 C 函数的 std::string_view