Is UB in unevaluated context (e.g. requires-expressions) still UB?

半世苍凉 提交于 2021-02-07 05:23:24

问题


The C++ 20 draft [concept.default.init] does not precisely define default_initializable

template<class T>
concept default_initializable = constructible_from<T> &&
    requires { T{}; } &&
    is-default-initializable <T>; // exposition-only

and describe what is-default-initializable should do with the following words:

For a type T, is-default-initializable <T> is true if and only if the variable definition

T t;

is well-formed for some invented variable t; otherwise it is false. Access checking is performed as if in a context unrelated to T. Only the validity of the immediate context of the variable initialization is considered.

On cppreference we find the following suggestion for a possible implementation:

template<class T>
concept default_initializable =
    std::constructible_from<T> &&
    requires { T{}; } &&
    requires { ::new (static_cast<void*>(nullptr)) T; };

The placement-new operator invoked with a nullptr argument results in undefined behavior.

9) Called by the standard single-object placement new expression. The standard library implementation performs no action and returns ptr unmodified. The behavior is undefined if this function is called through a placement new expression and ptr is a null pointer.

My question is now: is the suggested possible implementation actually valid? On the one hand I think no, because an expression is involved which exhibits undefined behavior. On the other hand I think yes, because this expression occurs in unevaluated context and therefore may not need to have well-defined behavior (?) and just needs to be syntactically valid. But I cannot find clear evidence for one or the other.

Second question: if the latter turns out to be true, then why does this placement-new construction satisfy the standard's requirement that T t; must be well-formed? To me it looks like a strange hack, because neither simple nor compound requirements offer the possibility to require T t; exactly. But why does this work?


回答1:


When specified, undefined behavior are the consequence of an evaluation [expr.new]/20

If the allocation function is a non-allocating form ([new.delete.placement]) that returns null, the behavior is undefined.

[expr.prim.req]/2:

Expressions appearing within a requirement-body are unevaluated operands.

[expr.prop]/1:

An unevaluated operand is not evaluated.

So there are no undefined behavior has it requires a return value of the placement new allocation function, but such value is not computed.

If it were not the case such common construct decltype( std::declval<int&>() + std::declval <int&> ()) would be UB too.



来源:https://stackoverflow.com/questions/62000436/is-ub-in-unevaluated-context-e-g-requires-expressions-still-ub

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!