【问题标题】:When are "return-by-reference" or "pass-by-reference" parameter compatible with constexpr?“return-by-reference”或“pass-by-reference”参数何时与 constexpr 兼容?
【发布时间】:2012-03-04 12:57:31
【问题描述】:

标记为 constexpr 的函数应该是不可变的纯函数。从"std::max() and std::min() not constexpr" 帖子中,您不能将 const-reference 输入重新引导为输出,因为这需要参数具有永久性。但是你可以通过const-reference 取一个参数,只要你不重新引导它吗?

// 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() ); }

相反,您能否将 const 引用返回到启用 constexpr 的类型的子对象?

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 ]; }
};

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

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

【问题讨论】:

    标签: c++ c++11 pass-by-reference constexpr


    【解决方案1】:

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

    §7.1.5 [dcl.constexpr] p3

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

    • [...]
    • 它的返回类型应该是文字类型;
    • 它的每个参数类型都应该是文字类型;
    • [...]

    §3.9 [basic.types] p10

    一个类型是一个文字类型如果它是:

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

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

    条件表达式是一个核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2),但逻辑与的子表达式(5.14) 、逻辑或 (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);或
    • [...]

    【讨论】:

    • 通过阅读,const T &amp; std::min(const T &amp;a, const T &amp;b) { return !(b&lt;a) : a : b ; } 应该是constexprable,但根据stackoverflow.com/questions/5605142/… 中接受的答案,它不应该。那么谁是对的呢?
    • @Marc:我的回答与 Johannes 的回答并不矛盾。正如 rsmith 对其他答案注释的评论一样,其他语言规则使 constexpr min/max 函数目前无法返回引用。
    • 好的,我咬紧牙关:哪一个?您列出了一些,但似乎没有一个禁止获取或返回参考。
    • @Marc:我认为 Johannes 的回答已经充分说明了这一点,我无法更好地表述它。这是第二个引用,也可以在 §5.19/3 中找到。
    【解决方案2】:

    Core issue 1454 的决议改变了 Johannes 在他对the std::max question 的回答中引用的规则。根据该问题的当前解决方案(由 g++ 和 clang 实现),constexpr 函数可以通过引用返回它们可以计算的任何左值。

    【讨论】:

    • 自这篇文章以来,对即将到来的 C++14 标准的constexpr 函数的限制已进一步放宽(通过(您的?)提案N3652)。尽管如此,在当前的最新草案(N3797)中,25.4.7 [alg.min.max] minmax 仍然不是 constexpr;有没有可能在最终发布之前“升级”?
    • @gx_ 我认为没有关于 C++14 草案的 NB 评论要求将 minmax 设为 constexpr,并且它不在 LWG 问题列表中,所以它不太可能发生在 C++14 上。委员会的一些成员一直在努力将constexpr 添加到所有相关的库函数中,所以这应该发生在 C++17 中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-08
    • 2016-09-04
    • 2015-10-22
    • 2022-02-24
    • 2018-08-12
    • 2016-11-15
    • 1970-01-01
    相关资源
    最近更新 更多