为啥这个 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 【问题描述】:我对@987654324@ 编程比较陌生,我正在尝试在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::find
是 constexpr
。
你刚刚添加了废弃的constexpr
godbolt.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 >= 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 类的构造函数[重复]