说下面 class Point 的默认构造函数是 constexpr 是否正确?

Is it correct to say that the default constructor for class Point below is constexpr?

乙。 Stroustrup 在他的书 "TCPL" 第 4 版的第 265 页有以下示例:

struct Point{
    int x, y, z;
    constexpr Point up(int d) { return {x, y, z+d}; }
    constexpr Poind move(int dx, int dy) { return {x+dx, y+dy}; }
};

在第 266 页的后面,他显示:

constexpr Point p1 {10, 20, 30};     // the default constructor is constexpr

从 N4140 的 §7.1.5/4 中,我发现以下相关要点:

  • (4.4) either its function-body shall be = default, or the compound-statement of its function-body shall satisfy the constraints for a function-body of a constexpr function;
  • (4.5) every non-variant non-static data member and base class sub-object shall be initialized (12.6.2);

关于上述要点,我有两个观察结果:

  1. 编译器为 struct Point 生成的默认构造函数具有函数体 = default 是否正确?
  2. 即使我上面的问题的答案是 yes,我也在争论编译器为 struct Point 生成的默认构造函数是 constexpr 的事实,只是因为这个构造函数没有' 初始化成员 xyz,与上面的要点 (4.5) 相矛盾。我说得对吗?

编辑我要介绍第三个问题,我认为它总结了我在这个问题上的主要困难。

我无法生成主体等于 = defaultconstexpr 默认构造函数的示例。假设这是不可能的。显而易见的问题是:§7.1.5/4 中的要点 (4.4) 的目的是什么?

  1. 是的。来自 [class.ctor]:

If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted (8.4).

隐式声明为默认的函数意味着它的功能就好像它被显式声明为 = default 一样。

  1. 你是对的。默认构造函数不能用作 constexpr,通过 [dcl.init]:
  2. 进一步明确

If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.

因此以下格式错误,因为没有用户提供的默认构造函数:

    constexpr Point p; // error

我们在 [dcl.constexpr] 中也看到了这一点:

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.20). Otherwise, or if a constexpr specifier is used in a reference declaration, every fullexpression that appears in its initializer shall be a constant expression. [ Note: Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization is part of such a full-expression. —end note ]
[ Example:

struct pixel {
    int x, y;
};
constexpr pixel ur = { 1294, 1024 };  // OK
constexpr pixel origin;               // error: initializer missing

—end example ]

由于默认构造函数不会为我们初始化(即使它没有满足用户提供的要求),我们可以提供一个初始化器来自己完成:

    constexpr Point q{}; // ok, all of q's members are 0

这一切最终都无关紧要,因为:

constexpr Point p1 {10, 20, 30};     // the default constructor is constexpr

根本不使用默认构造函数,实际上进行聚合初始化,满足上面引用的"shall be initialized"子句。