【问题标题】:Is the compiler generated constructor constexpr by default?编译器默认生成构造函数 constexpr 吗?
【发布时间】:2018-10-04 16:06:37
【问题描述】:

下面的代码compiles successfully同时带有clang++ 3.8.0g++ 7.2.0(编译标志是-std=c++14 -Wall -Wextra -Werror -pedantic-errors):

struct Foo
{
    constexpr operator bool() const
    {
        return false;
    }
};


int main()
{
    constexpr bool b = Foo{};

    (void)b;
}

编译器的这种行为是否符合标准?请注意,将任何成员(如int i;)添加到Foodoesn't change anything

【问题讨论】:

    标签: c++ constructor c++14 language-lawyer constexpr


    【解决方案1】:

    是的,隐式构造函数在这种情况下是 constexpr。一般来说,它取决于子对象。

    [class.ctor]

    一个默认的且未定义为已删除的默认构造函数在使用 odr 时被隐式定义(6.2) 创建其类类型(4.5)的对象或在其第一次声明后显式默认时。这 隐式定义的默认构造函数执行将要执行的类的一组初始化 通过该类的用户编写的默认构造函数,没有 ctor-initializer (15.6.2) 和一个空的复合 - 陈述。如果该用户编写的默认构造函数格式错误,则程序格式错误。 如果那样 用户编写的默认构造函数将满足 constexpr 构造函数 (10.1.5) 的要求, 隐式定义的默认构造函数是 constexpr。 ... [剪辑]

    constexpr构造函数的相关要求:

    [dcl.constexpr]

    • 该类不应有任何虚拟基类;
    • 对于非委托构造函数,选择每个构造函数来初始化非静态数据成员和 基类子对象应为 constexpr 构造函数;

    【讨论】:

    • Foo 的隐式声明的默认构造函数在 OP 的代码中确实是 constexpr,但这与编写的示例无关,因为 Foo{} 不调用任何构造函数;这是聚合初始化。 Foo() 也不会——这将是执行零初始化的值初始化,在 Foo 的情况下再次调用任何构造函数。如果添加成员 int i;,如 OP 所述,隐式声明的默认构造函数不再是 constexpr (因为它使 i 未初始化),但上述所有其他内容仍然有效,因此代码仍然有效。
    【解决方案2】:

    是的。编译器生成的默认构造函数,以及平凡的构造函数

    Foo() = default;
    

    both 使您能够编写constexpr bool b = Foo{};,假设所有类成员都可以构造constexpr。请注意,如果你写了

    Foo(){}
    

    那么constexpr不允许。 (default 与提供空主体的构造函数之间的重要区别。)

    【讨论】:

    • 您能否提供对标准文本的任何参考?
    • 查看我对其他答案的评论。另请注意,用户声明的 constexpr Foo() { } 对 OP 代码中的 Foo 有效(无非静态数据成员),但如果我们添加成员 int i; 则无效(它仍然适用于像 @ 这样的成员987654330@).
    猜你喜欢
    • 2020-09-25
    • 2014-03-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    相关资源
    最近更新 更多