【问题标题】:constexpr and mutable member and implicit copy-ctorconstexpr 和 mutable 成员和隐式 copy-ctor
【发布时间】:2020-01-09 21:40:33
【问题描述】:

以下代码在 clang 7+ 中编译,但在 5 和 6 中不编译(使用 c++17 和 c++14)。 clang 5 和 6 的问题似乎是隐式复制 ctor 从可变成员 x 读取。

谁能告诉我,整个结构是否符合标准(c++17),或者程序是否格式错误?还是在较早的 clang 版本中可能无法实现的隐式 copy-ctor 的标准发生了变化?

struct Foo {

    int a;
    mutable int x{};

    constexpr Foo() : a(0) {}

    //constexpr Foo(const Foo& other) : a(other.a) {} // <- with this line it works on Clang 5 & 6, too
};

struct FooFactory {

    static constexpr auto create() {
        auto f = Foo{};       
        return f;
    }
};

int main() {

    constexpr Foo f = FooFactory::create();
    ++f.x;
}

直播代码here.

【问题讨论】:

    标签: c++ language-lawyer c++17 copy-constructor constexpr


    【解决方案1】:

    这是一个格式良好的 C++17 程序。 constexpr 函数当然可以读取(和写入)非常量变量:

    constexpr int f(int i) {
      int j=i;
      ++j;
      return i+j;  // neither is a constant expression
    }
    

    rule 是在常量表达式中检查的任何内容都必须是常量其生命周期开始表达式的评估期间。在您的情况下,createf.x 的生命周期显然始于对 mainf初始化 常量表达式的求值。然而,确实没有Foo 对象可以被不创建该对象的常量表达式复制,无论它是否为constexpr

    唯一的其他候选问题是如果复制构造函数不是 constexpr,但这些要求非常。唯一相关的是每个(非变体)成员都被初始化,这当然是令人满意的,并且它可以在至少一个常量表达式中使用,这已经被证明了。

    【讨论】:

    • 非常有趣,谢谢。我提到了一个非常量成员的读取,因为这是在 this-is-not-a-constant-expression-error 之后的 note clang 6 printet。
    【解决方案2】:

    代码格式不正确。作为参考,这里是简化的代码,在所有编译器上都失败了:

    struct Foo {
        int a;
        mutable int x{};
        constexpr Foo() : a(0) {}
    
    };
    
    int main() {
        constexpr Foo f;
        constexpr Foo f1 = f;
    }
    

    根据 [expr.const] 7.7,

    变量在初始化后可用于常量表达式 如果遇到声明 它是一个 constexpr 变量,

    或 ... (3.5) 一个不可变的 上述任何一个的子对象或引用成员。

    这会取消默认的复制构造函数。

    【讨论】:

    • Clang 可能不会抱怨 OP 的代码,因为 NRVO 启动了。添加 constexpr Foo f1 = f; 确实会导致错误。
    • 很好,这似乎是原因!谢谢你们!
    • 这种简化似乎并不等同。 constexpr 函数不需要只使用常量表达式。如我所见,原始工厂函数调用Foo的默认构造函数来生成f,然后使用复制构造函数初始化其返回对象。两者都不需要f 可以在常量表达式中使用。初始化constexpr Foo f = FooFactory::create() 不直接调用任何构造函数。 f 由调用的评估初始化。因此,f 初始化的完整表达式只是对constexpr 函数的调用,这是允许的。
    • 那是 [expr.const]/3,不是 7.7,是 C++20 草案的一部分,不是 17,而且项目符号对应的不是变量,而是对象或引用。
    猜你喜欢
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 2016-07-03
    • 2017-04-08
    • 1970-01-01
    相关资源
    最近更新 更多