![](/img/trans.png)
[英]constexpr std::vector and constexpr std::string in C++20
[英]What is the reason for std::memcpy not being constexpr even in C++20?
我知道在编译时并不总是可以复制任意的内存块,但是既然我们得到了 constexpr 容器、虚拟方法和算法,那么为什么不使用 memcpy 呢? 这也是一种算法。
此外,
std::bit_cast
看起来很像std::memcpy
解决方法reinterpret_cast
但它是constexpr
。std::copy
被标记为 C++20 的constexpr
,因此复制对于类型来说是可能的。 用法是在constexpr
函数中复制或只是“重新解释”变量/数组,前者不是由std::bit_cast
AFAIK 解决的。 特别是这个问题和我的答案想使用它。
std::bit_cast
可以是 constexpr 而std::memcpy
不能?std::bit_cast
的引用参数和std::copy
迭代器。C++20 bit_cast vs reinterpret_cast 的相关答案从某处简要引用:
此外,目前不可能实现 constexpr 位转换函数,因为 memcpy 本身不是 constexpr。 将建议的函数标记为 constexpr 不需要或阻止 memcpy 成为 constexpr,但需要编译器支持。 这使得实现可以自由地使用他们自己的内部解决方案(例如,LLVM 有一个位播操作码)。
但它没有详细说明不使其成为 constexpr。
请注意,我不问为什么std::bit_cast
存在。 我喜欢它,它提供了一个明确的意图,而不是std::memcpy
解决方法。
运行时代码中的 C++ 对象模型通常处理得有些松散。 它有相当严格的规则,但有一堆后门要么被允许,要么被宣布为 UB。 后者意味着您仍然可以编写代码来执行此操作,但 C++ 对该代码的行为没有任何保证。
在不断评估(又名:代码的编译时执行)中,情况并非如此。 constexpr
的限制专门用于允许对象模型成为您必须遵循的真实事物,没有可行的后门。 甚至它偶尔允许的那些也明确要求格式错误并产生编译错误,而不是静默 UB。
基本上在运行时,您可以将内存视为存储字节。 在编译时,你不能; 你不被允许。 即使在 C++20 中添加了constexpr
代码中的动态分配,您也不会玩很多通常会玩那种东西的游戏。
memcpy
处理存储字节数,来回复制它们而不知道它们的含义。 bitcast
知道源对象和目标对象,除非源对象和目标对象适合bitcast
ing(即:可简单复制),否则它不允许您这样做。
如果您希望它在编译时工作, bitcast
对这两个对象的内容也有非常具体的限制。 特别是,您不能bitcast
指针或包含任何类型指针的任何对象进行位转换。 或者参考。
这是因为编译时的指针不仅仅是地址。 为了捕获 UB,编译时指针必须知道它指向的对象的真实动态类型。 所以在编译时不允许只转换地址的指针转换。
这更多是评论然后是答案,因为我只是引用了P0202R0 中写的内容:将 Constexpr 修饰符添加到函数和标题中,但我在这里写的不符合评论:
B.
std::memmove
和std::memcpy
必须添加 constexpr
std::memmove
和std::memcpy
接受void*
和const void*
参数。 这使得它们无法在纯 C++ 中实现为constexpr
,因为常量表达式无法根据 [expr.const] 评估从类型cv void *
到指向对象类型的转换。
然而,这些函数不仅流行,而且在标准库中广泛使用以获得更好的性能。 不使它们 constexpr 将迫使标准库开发人员无论如何都为它们提供编译器内在函数。 这是必须完成的艰难步骤。
[expr.const]
的相关部分:
8.6 常量表达式 [expr.const]
[…]表达式e
是核心常量表达式,除非按照抽象机 (6.8.1) 的规则对e
求值,会求值以下表达式之一:
[…]
(2.13) — 从cv void*
类型到指向对象类型的转换;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.