简体   繁体   English

编译时评估代码中的重言式是否保证被执行/优化掉?

[英]Are tautologies in compile-time evaluated code guaranteed to be executed / optimized away?

Is the compiler guaranteed to evaluate boolean constexpr expressions that are "tautologies" (eg always true or false respectively) in a constexpr environment?编译器是否保证在constexpr环境中评估"tautologies" (例如,始终分别为truefalse )的布尔型constexpr表达式?

Minimal Example / Clarification最小示例/说明

For example, in the following code snipplet (at the line marked with (1) ) I invoke a function in a constexpr environment, which I intend to cause a compile time error whenever a non-constexpr function is passed.例如,在以下代码片段中(在标有(1) )我在constexpr环境中调用一个函数,我打算在传递non-constexpr函数时导致编译时错误。 At least the compiler I use ( g++-10.0 ) does this, even though it could also realize that the expression is always true without evaluating it.至少我使用的编译器 ( g++-10.0 ) 是这样做的,即使它也可以意识到表达式始终为true而不求值。 The reason I ask this question, is because -- to the best of my knowledge -- in a non-constepxr context, an expression like i >= std::numeric_limits<int>::min() is optimized away to true for an int i .我问这个问题的原因是——据我所知——在非 constepxr 上下文中,像i >= std::numeric_limits<int>::min()这样的表达式被优化为true for一个int i

#include <limits>
constexpr int example_function() { return 1;}
constexpr bool compileTimeErrorDesired = example_function() || true; // (1)

Application Example应用实例

If the behavior in (1) is guaranteed, it can for instance be used in a concept , in order to execute different code, depending on whether a function provided as template argument can be evaluated at compile time.如果(1)的行为得到保证,则它可以例如用于concept ,以执行不同的代码,具体取决于作为模板参数提供的函数是否可以在编译时求值。 I implemented a very short ( 7 lines-of-code ) example which does exactly that here at compiler explorer .我实现了一个非常短的( 7 lines-of-code )示例,它在编译器资源管理器中完全做到这一点。

Question

Is the line (1) guaranteed to cause a compile time error if called with a non-constexpr function?如果使用非 constexpr 函数调用,行 (1) 是否保证会导致编译时错误?

edit Inserted clarification, simplify example due to feedback.编辑插入澄清,由于反馈而简化示例。

It's guaranteed that f() || true保证f() || true f() || true is not a core constant expression if f is not a constexpr function: (constant expressions are more restrictive than core constant expressions) [expr.const]/2.2如果f不是 constexpr 函数,则f() || true不是核心常量表达式:(常量表达式比核心常量表达式更具限制性) [expr.const]/2.2

An expression e is a core constant expression unless the evaluation of e , following the rules of the abstract machine , would evaluate one of the following expressions:表达式e核心常量表达式,除非e的计算遵循抽象机器的规则,将计算以下表达式之一:

  • [...] [...]

  • an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor ([class.dtor]) [ Note: Overload resolution is applied as usual — end note ];比constexpr构造为一个文字类,一个constexpr函数,或一个简单的析构函数的隐式调用其它的函数的调用([class.dtor])[注:重载分析被用于像往常一样-注完];

  • [...] [...]

It's also guaranteed that the program is ill-formed (diagnostic required) if non-constant expressions are used in contexts that require constant expressions.如果在需要常量表达式的上下文中使用非常量表达式,还可以保证程序格式错误(需要诊断)。 Note that ||注意|| is defined to evaluate from left to right: [expr.log.or]/1定义为从左到右计算: [expr.log.or]/1

The || || operator groups left-to-right.运算符组从左到右。 The operands are both contextually converted to bool .操作数都根据上下文转换为bool It returns true if either of its operands is true , and false otherwise.如果其任一操作数为true ,则返回true否则返回false Unlike |不像| , || , || guarantees left-to-right evaluation;保证从左到右的评估; moreover, the second operand is not evaluated if the first operand evaluates to true.此外,如果第一个操作数的计算结果为真,则不会计算第二个操作数。

In other words, true || f()换句话说, true || f() true || f() is a core constant expression because f() is not evaluated, whereas f() || true true || f()是一个核心常量表达式,因为f()不被计算,而f() || true f() || true is not because f() is evaluated. f() || true不是因为f()被评估。

Whether or not an expression is a constant expression has nothing to do with optimization — constant expressions are defined based on the rules of the abstract machine.表达式是否为常量表达式与优化无关——常量表达式是根据抽象机器的规则定义的。

The terms "executed" isn't exactly appropriate when it comes to constant expressions.当涉及到常量表达式时,术语“执行”并不完全合适。 Even "evaluated" might be used with care, because whether an expression is a constant expression depends partly on behavior of what would happen if the expression were evaluated, but is not considered an evaluation in the most strict sense.甚至“求值”也可能要小心使用,因为表达式是否为常量表达式部分取决于如果对表达式求值会发生什么情况,但在最严格的意义上不被视为求值。

[expr.const] describes requirements for a number of different contexts of "compile-time behavior", including "constant expression". [expr.const]描述了“编译时行为”的许多不同上下文的要求,包括“常量表达式”。 [expr.const]/(5.2) says that if evaluating an expression would evaluate a non-constexpr function, the expression is not a core constant expression, and therefore not a constant expression. [expr.const]/(5.2) 表示如果计算表达式会计算非 constexpr 函数,则该表达式不是核心常量表达式,因此也不是常量表达式。 If the expression is used in a context requiring a constant expression (like static_assert , a non-type template argument, etc.), the program is ill-formed and there must be a diagnostic message.如果在需要常量表达式的上下文中使用表达式(如static_assert 、非类型模板参数等),则程序static_assert ,并且必须有诊断消息。 There is no rule permitting anything like allowing a non-constant expression in such a context or skipping some parts of the hypothetical evaluation if the expression is a converted constant expression and the result value of the expression can be determined despite not being a constant expression.没有规则允许在这样的上下文中允许非常量表达式或跳过假设评估的某些部分,如果表达式是转换后的常量表达式,并且表达式的结果值可以确定,尽管它不是常量表达式。

So if example_function is not declared constexpr , then example_function() || true因此,如果example_function未声明为constexpr ,则example_function() || true example_function() || true is not a constant expression because the evaluation would require calling the function. example_function() || true不是常量表达式,因为计算需要调用函数。 But true || example_function()true || example_function() true || example_function() is a constant expression, since the evaluation would not call the function. true || example_function()是一个常量表达式,因为评估不会调用该函数。

Your is_constexpr<T> is guaranteed to work, because any semantic constraint violation involving a template parameter inside a requires-expression does not make the program ill-formed, but just makes the requires-expression result value false ( [expr.prim.req]/6 ).您的is_constexpr<T>保证可以工作,因为任何涉及requires-expression中的模板参数的语义约束违规都不会使程序格式false ,而只会使requires-expression结果值为false ( [expr.prim.req ]/6 )。 In is_constexpr<example_function> , using the non-constant expression T() as a template argument to std::enable_if via the default template argument instantiated by ConstexprHelper<T> is such a semantic error, so the requires-expression has value false .is_constexpr<example_function> ,通过ConstexprHelper<T>实例化的默认模板参数使用非常量表达式T()作为std::enable_if的模板参数是这样的语义错误,因此requires-expression 的值为false

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

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