2

标记为 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() ); }

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

或者甚至子对象的回报也必须是按价值计算的?

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

4

2 回答 2

4

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

§7.1.5 [dcl.constexpr] p3

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

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

§3.9 [basic.types] p10

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

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

因此,是的,您可以拥有引用参数,甚至是对非 const 的引用。函数的参数constexpr以另一种方式受到限制。完整、详尽的列表可在下方找到§5.19 [expr.const] p2constexpr以下是使声明的函数不再如此的摘录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);或者
  • [...]
于 2012-02-13T04:27:59.890 回答
1

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

于 2012-03-02T06:18:36.360 回答