简体   繁体   English

即使在 C++20 中 std::memcpy 也不是 constexpr 的原因是什么?

[英]What is the reason for std::memcpy not being constexpr even in C++20?

I understand that copying arbitrary chunks of memory is not always possible to do at compile time but since we are getting constexpr constainers, virtual methods and also algorithms, why not memcpy too?我知道在编译时并不总是可以复制任意的内存块,但是既然我们得到了 constexpr 容器、虚拟方法和算法,那么为什么不使用 memcpy 呢? It is too a kind of algorithm.这也是一种算法。

Furthemore,此外,

  • C++20 std::bit_cast seems a lot like std::memcpy workaround reinterpret_cast but it is constexpr . C++20 std::bit_cast看起来很像std::memcpy解决方法reinterpret_cast但它是constexpr
  • std::copy using iterators is marked as constexpr for C++20, so copying is somehow possible for types.使用迭代器的std::copy被标记为 C++20 的constexpr ,因此复制对于类型来说是可能的。

The usage would be to either copy or just "reinterpret" variables/arrays in constexpr functions, the former is not solved by std::bit_cast AFAIK.用法是在constexpr函数中复制或只是“重新解释”变量/数组,前者不是由std::bit_cast AFAIK 解决的。 In particular, the question and my answer would like to use it.特别是这个问题和我的答案想使用它。

  • Is there any particular reason for why std::bit_cast can be constexpr but std::memcpy cannot?为什么std::bit_cast可以是 constexpr 而std::memcpy不能?
  • Does it have to do with memcpy using void pointers instead of typed references?它是否与使用空指针而不是类型化引用的 memcpy 有关?
  • Not actually having to copy anything?实际上不必复制任何东西?
  • C backwards compatibility? C 向后兼容?
  • Maybe because there is no support for a "pointer to constexpr memory"?也许是因为不支持“指向 constexpr 内存的指针”? But the same applies to the reference parameter in std::bit_cast and iterators in std::copy .但同样适用于std::bit_cast的引用参数和std::copy迭代器。

Relevant answer to C++20 bit_cast vs reinterpret_cast briefly cites from somewhere: C++20 bit_cast vs reinterpret_cast 的相关答案从某处简要引用:

Furthermore, it is currently impossible to implement a constexpr bit-cast function, as memcpy itself isn't constexpr.此外,目前不可能实现 constexpr 位转换函数,因为 memcpy 本身不是 constexpr。 Marking the proposed function as constexpr doesn't require or prevent memcpy from becoming constexpr, but requires compiler support.将建议的函数标记为 constexpr 不需要或阻止 memcpy 成为 constexpr,但需要编译器支持。 This leaves implementations free to use their own internal solution (eg LLVM has a bitcast opcode).这使得实现可以自由地使用他们自己的内部解决方案(例如,LLVM 有一个位播操作码)。

But it does not go into detail of not making it constexpr too.但它没有详细说明不使其成为 constexpr。

Note, that I do not ask for why std::bit_cast exists.请注意,我不问为什么std::bit_cast存在。 I like it, it provides a clear intention instead of std::memcpy workaround.我喜欢它,它提供了一个明确的意图,而不是std::memcpy解决方法。

The C++ object model in runtime code is generally treated somewhat loosely.运行时代码中的 C++ 对象模型通常处理得有些松散。 It has fairly strict rules, but there are a bunch of backdoors that are either allowed or declared UB.它有相当严格的规则,但有一堆后门要么被允许,要么被宣布为 UB。 The latter means that you can still write code to do it, but C++ guarantees nothing about the behavior of that code.后者意味着您仍然可以编写代码来执行此操作,但 C++ 对该代码的行为没有任何保证。

Within constant evaluation (aka: compile-time execution of code), this is not the case.在不断评估(又名:代码的编译时执行)中,情况并非如此。 The restrictions on constexpr are specifically intended to allow the object model to be a real thing that you must follow, with no viable backdoors. constexpr的限制专门用于允许对象模型成为您必须遵循的真实事物,没有可行的后门。 And even the ones that it occasionally permits are explicitly required to be ill-formed and produce a compile-error, rather than being silent UB.甚至它偶尔允许的那些也明确要求格式错误并产生编译错误,而不是静默 UB。

Basically at runtime, you get to treat memory as just bytes of storage.基本上在运行时,您可以将内存视为存储字节。 At compile-time, you can't ;在编译时,你不能 you're not allowed to.你不被允许。 Even with dynamic allocation in constexpr code added in C++20, you don't get to play a lot of the games you usually get to play with that sort of thing.即使在 C++20 中添加了constexpr代码中的动态分配,您也不会玩很多通常会玩那种东西的游戏。

memcpy deals in bytes of storage, copying them back and forth with no idea what they mean. memcpy处理存储字节数,来回复制它们而不知道它们的含义。 bitcast knows both the source and destination objects, and it will not allow you to do it unless the source and destination objects are appropriate for bitcast ing (ie: trivially-copyable). bitcast知道源对象和目标对象,除非源对象和目标对象适合bitcast ing(即:可简单复制),否则它不允许您这样做。

bitcast also has very specific restrictions on the content of both such objects if you want it to work at compile-time.如果您希望它在编译时工作, bitcast对这两个对象的内容也有非常具体的限制 In particular, you can't bitcast pointers or any objects containing pointers of any kind.特别是,您不能bitcast指针或包含任何类型指针的任何对象进行位转换。 Or references.或者参考。

This is because pointers at compile-time are not just addresses.这是因为编译时的指针不仅仅是地址。 In order to catch UB, a compile-time pointer has to know the true dynamic type of the object it points to.为了捕获 UB,编译时指针必须知道它指向的对象的真实动态类型。 So pointer conversions that just convert the address aren't allowed at compile-time.所以在编译时不允许只转换地址的指针转换。

That's more a comment then an answer as I'm only citing what is written in P0202R0: Add Constexpr Modifiers to Functions in and Headers , but I write it here as is does not fit the comments:这更多是评论然后是答案,因为我只是引用了P0202R0 中写的内容:将 Constexpr 修饰符添加到函数和标题中,但我在这里写的不符合评论:

B. std::memmove and std::memcpy must have constexpr additions B. std::memmovestd::memcpy必须添加 constexpr
std::memmove and std::memcpy accept void* and const void* parameters. std::memmovestd::memcpy接受void*const void*参数。 This makes them impossible to implement in pure C++ as constexpr , because constant expressions can not evaluate a conversion from type cv void * to a pointer-to-object type according to [expr.const].这使得它们无法在纯 C++ 中实现为constexpr ,因为常量表达式无法根据 [expr.const] 评估从类型cv void *到指向对象类型的转换。
However those functions are not only popular, but also are widely used across Standard Library to gain better performance.然而,这些函数不仅流行,而且在标准库中广泛使用以获得更好的性能。 Not making them constexpr will force standard Library developer to have compiler intrinsics for them anyway.不使它们 constexpr 将迫使标准库开发人员无论如何都为它们提供编译器内在函数。 This is a hard step that must be done.这是必须完成的艰难步骤。

The related section of [expr.const] : [expr.const]的相关部分:

8.6 Constant expressions [expr.const] 8.6 常量表达式 [expr.const]
[…]An expression e is a core constant expression unless the evaluation of e , following the rules of the abstract machine (6.8.1), would evaluate one of the following expressions: […]表达式e核心常量表达式,除非按照抽象机 (6.8.1) 的规则对e求值,会求值以下表达式之一:
[…] […]
(2.13) — a conversion from type cv void* to a pointer-to-object type; (2.13) — 从cv void*类型到指向对象类型的转换;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM