何时“按引用返回”?或“按引用传递”参数与 constexpr 兼容吗?

发布于 2025-01-05 02:19:21 字数 1033 浏览 0 评论 0原文

标记为 constexpr 的函数应该是不可变的纯函数。来自 “std::max() 和 std::min() 不是 constexpr” post,您不能将常量引用输入重新引导为输出,因为这需要参数具有永久性。但是,只要不重新引导它,您可以通过 const 引用获取参数吗?

// Is this still constexpr?
// (Assuming that std::complex is constexpr-safe, as it's supposed to be.)
constexpr
int  MySum( std::complex<double> const &a, std::complex<double> const &b )
{ return static_cast<int>( a.real() + b.real() ); }

相反,您可以返回对启用 constexpr 的类型的子对象的 const 引用吗?

template <typename T>
class MyComplex
{
    T  c_[ 2 ];
public:
    constexpr MyComplex( T r = T(), T i = T() )
    : c_{ r, i }
    {}

    // Is this actually constexpr?
    constexpr T const &  operator[]( unsigned l ) //const
    { return c_[ l ]; }

    // Can't be constexpr
    T &  operator[]( unsigned l )  { return c_[ l ]; }
};

或者甚至子对象返回也必须按值返回?

(抱歉,如果这是基本的,但我发现的所有内容都围绕这一点跳舞,但实际上并没有确定。)

Functions marked constexpr are supposed to be immutable pure functions. From the "std::max() and std::min() not constexpr" post, you can't re-channel a const-reference input as an output, since that would require the parameter to have permanence. But can you take a parameter by const-reference, as long as you don't re-channel it?

// Is this still constexpr?
// (Assuming that std::complex is constexpr-safe, as it's supposed to be.)
constexpr
int  MySum( std::complex<double> const &a, std::complex<double> const &b )
{ return static_cast<int>( a.real() + b.real() ); }

Conversely, can you return a const-reference to a sub-object of a constexpr-enabled type?

template <typename T>
class MyComplex
{
    T  c_[ 2 ];
public:
    constexpr MyComplex( T r = T(), T i = T() )
    : c_{ r, i }
    {}

    // Is this actually constexpr?
    constexpr T const &  operator[]( unsigned l ) //const
    { return c_[ l ]; }

    // Can't be constexpr
    T &  operator[]( unsigned l )  { return c_[ l ]; }
};

Or do even sub-object returns have to be by value?

(Sorry if this is basic, but everything I've found dances around this point without actually being definitive.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

顾挽 2025-01-12 02:19:21

该标准对于 constexpr 函数中允许的内容非常清楚:

§7.1.5 [dcl.constexpr] p3

constexpr函数的定义应满足以下约束:

  • [...]
  • 其返回类型应为文字类型;
  • 其每个参数类型均应为文字类型;
  • [...]

§3.9 [基本类型] p10

如果满足以下条件,则类型是文字类型

  • 标量类型;或
  • 引用类型;
  • 具有以下所有属性的类类型(第 9 条):
  • 它有一个简单的析构函数,
    • 非静态数据的大括号或等于初始化程序中的每个构造函数调用和完整表达式
      成员(如果有)是常量表达式(5.19),
    • 它是一种聚合类型 (8.5.1) 或至少有一个 constexpr 构造函数或构造函数模板
      这不是复制或移动构造函数,并且
    • 它拥有所有非静态数据成员和文字类型的基类;或
  • 文字类型的数组。

因此,是的,您可以拥有引用参数,甚至是对非常量参数的引用。 constexpr 函数的参数以另一种方式受到限制。完整、详尽的列表可以在§5.19 [expr.const] p2下找到。下面摘录了 constexpr 声明的函数不再那么constexpr 的原因:

条件表达式核心常量表达式,除非它涉及以下内容之一作为潜在计算的子表达式 (3.2),但逻辑 AND 的子表达式 (5.14)不考虑未计算的逻辑 OR (5.15) 和条件 (5.16) 运算 [注意: 重载运算符调用函数。 —尾注]:

关于逻辑运算符的最后一点只是意味着它的未计算部分(由于短路计算)不是确定该函数是否真正<代码> constexpr 。)

  • [...]
  • 动态演员表 (5.2.7);
  • reinterpret_cast (5.2.10);
  • 伪析构函数调用 (5.2.4);
  • 递增或递减运算(5.2.6、5.3.2);
  • 一个 typeid 表达式 (5.2.8),其操作数是多态类类型;
  • 一个新表达式 (5.3.4);
  • 删除表达式 (5.3.5);
  • 减法 (5.7),其中两个操作数都是指针;
  • 结果未指定的关系运算符 (5.9) 或相等运算符 (5.10);
  • 赋值或复合赋值 (5.17);或
  • [...]

The standard is pretty clear on what is allowed in a constexpr function:

§7.1.5 [dcl.constexpr] p3

The definition of a constexpr function shall satisfy the following constraints:

  • [...]
  • its return type shall be a literal type;
  • each of its parameter types shall be a literal type;
  • [...]

§3.9 [basic.types] p10

A type is a literal type if it is:

  • a scalar type; or
  • a reference type; or
  • a class type (Clause 9) that has all of the following properties:
  • it has a trivial destructor,
    • every constructor call and full-expression in the brace-or-equal-initializers for non-static data
      members (if any) is a constant expression (5.19),
    • it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template
      that is not a copy or move constructor, and
    • it has all non-static data members and base classes of literal types; or
  • an array of literal type.

As such, yes, you can have reference parameters, even reference-to-non-const ones. The parameters of a constexpr function are restricted in another way. The complete, exhaustive list can be found under §5.19 [expr.const] p2. Here's an excerpt of what makes a constexpr declared function not-so-constexpr anymore:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [ Note: An overloaded operator invokes a function. —end note ]:

(The last bit about the logical operators just means that the unevaluated part of it (due to short-circuit evaluation) is not part of the operations that determine whether the function is truly constexpr.)

  • [...]
  • a dynamic cast (5.2.7);
  • a reinterpret_cast (5.2.10);
  • a pseudo-destructor call (5.2.4);
  • increment or decrement operations (5.2.6, 5.3.2);
  • a typeid expression (5.2.8) whose operand is of a polymorphic class type;
  • a new-expression (5.3.4);
  • a delete-expression (5.3.5);
  • a subtraction (5.7) where both operands are pointers;
  • a relational (5.9) or equality (5.10) operator where the result is unspecified;
  • an assignment or a compound assignment (5.17); or
  • [...]
风轻花落早 2025-01-12 02:19:21

核心问题 1454 的解决方案更改了约翰内斯在他对 std::max 问题。通过该问题的当前解决方案(由 g++ 和 clang 实现),constexpr 函数可以通过引用返回它们可以计算的任何左值。

Core issue 1454's resolution changes the rule which Johannes is referencing in his answer to the std::max question. With the current resolution of that issue (which is implemented by both g++ and clang), constexpr functions are allowed to return, by reference, any lvalue which they can compute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文