nullptr_t是默认的可构造类型吗?

Thr*_*Bit 16 c++ gcc clang nullptr

我无法从C++ 11标准中看出nullptr_t是否有默认构造函数.换句话说,以下是否有效?:

nullptr_t n; 
Run Code Online (Sandbox Code Playgroud)

GCC和VC++允许上面的代码,但clang没有.我在标准中找不到任何指定它没有默认构造函数的东西,我能找到它表明它应该.这对我很重要,因为我正在为较旧的编译器支持编写nullptr的基本回退实现,并且需要知道是否需要为其提供默认构造函数.

Com*_*sMS 17

标准说的是什么

标准说(18.2)

nullptr_t定义如下:

namespace std {
   typedef decltype(nullptr) nullptr_t;
}
Run Code Online (Sandbox Code Playgroud)

nullptr_t是同义词的类型具有3.9.1和4.10中描述的特征.

其中3.9.1基本上表示它应该void*和4.10规定的转换规则相同nullptr.

编辑: 3.9.9进一步明确声明这nullptr_t是一个标量类型,这意味着8.5的内置类型的预期初始化规则适用:

  • Default-initialization(nullptr_t n;),它保留nundefined 的值.正如Johannes Schaub正确指出的那样,这与最新版本的Clang编译得很好.
  • 值初始化(nullptr_t n = nullptr_t();),将n初始化为0.

这种行为与例如相同int,因此nullptr_t绝对是可构造的.这里有趣的问题是:nullptr_t具有未定义的值意味着什么?在一天结束时,只有一个有意义的可能值nullptr_t,即nullptr.此外,类型本身仅通过nullptr文字的语义来定义.这些语义是否仍然适用于单一化值?

为什么这个问题在实践中无关紧要

您不希望声明类型的新变量nullptr_t.该类型唯一有意义的语义已经通过nullptr文字表达,因此无论何时使用类型的自定义变量nullptr_t,您都可以使用nullptr.

在实践中有什么关系

唯一的例外是你可以采用类型的非类型模板参数nullptr_t.对于这种情况,知道哪些值可以转换为有用nullptr_t,这在4.10中描述:

空指针常量是整数类型的整数常量表达式(5.19)prvalue,其计算结果为零或类型的prvalue std::nullptr_t.[...]整数类型的空指针常量可以转换为类型的prvalue std::nullptr_t.

这基本上就是你所期望的:你可以写

nullptr_t n = 0;    // correct: 0 is special
Run Code Online (Sandbox Code Playgroud)

但不是

nullptr_t n = 42;   // WRONG can't convert int to nullptr_t
Run Code Online (Sandbox Code Playgroud)

gcc 4.6和Clang SVN都是正确的.

  • @ComicSansMS - 再次取得良好进展.谢谢.在使用值初始化语法时,它们是值初始化的,但我想我得到了你想说的内容.无论如何,还有另外一点,答案仍然具有误导性.未初始化的值绝对不一定是`nullptr`.未初始化的`bool`可能包含`true`,`false`或任何其他位模式,并且使用这种"第三值"的计算是未定义的,并且可能导致逻辑上"不可能"的分支路径.我怀疑但是没有检查过这个新的未命名类型是否相同(编译器可能会发出警告). (2认同)
  • @etherice我不认为它对用户有所影响,但我认为这使得更容易掌握规范(个人意见). (2认同)
  • @JirkaHanika:还有一件事:当你说"...默认初始化如int x = new int(); ..."时,你没有使用正确的术语.`int()`是`value-initialization`,而不是`default-initialization`.Per C++11§8.5.10:`一个对象,其初始化器是一组空的括号,即(),应进行值初始化.每个8.5.7(总结):'POD类型的值初始化是零initialization`.每个8.5.11:`如果没有为一个对象指定初始化器,则该对象是默认初始化的.每个8.5.6(总结):`POD类型的默认初始化是什么都不做. (2认同)