const-default-constructable 对象可以是非类类型吗?



根据我的理解,对于类类型T是const-default-constructable类型,T的默认初始化应调用用户提供的构造函数,或者T应为每个非变体非静态数据成员提供默认成员初始值设定项:([dcl.init]/7)

类类型Tconst-default-constructable如果T的默认初始化将调用用户提供的构造函数T(不是从基类继承的)或如果

  • (7.4) 每个直接 非变量非静态数据成员MT具有默认成员 初始值设定项 [..]

注意到粗体部分,在我看来,const-default-constructable 类型只能是类类型(包括联合和结构)。因此,我不能说const int,例如,是 const-default-constructable 类型,因为int不是类类型。

你可能会问,这种困惑是从哪里来的。基本上,[class.default.ctor]/2 说:

X的默认构造函数定义为已删除 如果:

  • [..]
  • (2.4)任何没有大括号或等于初始值设定项const 限定类型(或其数组)的非变量非静态数据成员都不是const-default-constructible([dcl.init]),
  • [..]

请注意">任何"一词。此项目符号考虑X具有数据成员M的情况,并且M是类类型和非类类型。但是根据 [dcl.init]/7,const-default-constructable 类型仅限于类类型。

考虑以下示例,

struct S
{
const int I;
// Is the type of S::I said to be non-const-default-constructible?
S() = default;
};

是否有缺少措辞?我看错了引号吗?


PS:感谢@463035818_is_not_a_number澄清这一点。考虑这种情况:

struct X
{
const int M = 0;
// Is the type of X::M said to be const-default-constructible?
X() = default;
};

S::I 的类型是非常量默认可构造的吗?

是的。 就像你在 [dcl.init]/7 中引用的那样,只有类类型可以是const-default-constructable。 这样做的原因是非类类型没有默认构造函数,这意味着它们没有默认值,如果它们被声明为

const T foo;

当你阅读时

任何没有大括号或等于初始值设定项的 const 限定类型(或其数组)的非变体非静态数据成员都不是const-default-constructable([dcl.init])

它的意思是,如果您的类中有一个const T name;形式的成员,那么如果T不是 const 默认构造函数,则默认构造函数将被删除。 在您的情况下,这意味着您的构造函数被删除const int因为它不是常量默认可构造的。


X的情况下,M仍然不是const-default-constructable,因为它不是一个类类型。X虽然是const-default-constructable的,M有一个大括号或等于的初始值设定项,所以[class.default.ctor]/2.4不适用。


这可以归结为一个简单的规则:所有 const 对象都必须有一个初始值设定项

由于内置类型不会默认初始化,因此它们必须具有程序员提供的值。

非类类型永远不会是常量默认构造的,因为你已经正确阅读了。

但我不认为有任何措辞缺失。这似乎是故意的。const-default-constructable的全部意义在于确保在初始化后不会意外地将对象保留不确定值,而以后无法更改该对象的值。

在初始化后尝试更改I的值将是 UB(因为它被声明为const),但是使用默认的默认构造函数或I没有显式初始值设定项,它将被默认初始化为不确定值(因为这是默认初始化对非类类型的影响),然后无法更改。不确定的值几乎不能用于任何用途。该标准甚至不允许复制它(除了类型unsigned charstd::byte)。

因此,没有理由允许您使用默认的默认构造函数默认构造此S

(从技术上讲,该标准现在允许使用放置new透明地替换I对象,只要它不是 const 完备对象的一部分,这允许在某种意义上更改其值,但这不应该是一个正常的用例。

相关内容

最新更新