我不明白为什么以下代码编译?
int main()
{
//int a = nullptr; // Doesn't Compile
//char b = nullptr; // Doesn't Compile
bool c = nullptr; // Compiles
return 0;
}
而评论部分则没有。
我已经经历了这个和这个。
bool
和nullptr
都是关键字,那么其他数据类型有什么独特之处呢?
出于与
if( p ) { ... }
编译:基本类型的任何值都隐式转换为布尔值,0
转换为false
,任何其他值转换为true
。
最初,基本类型值必须转换为bool
以实现 C 兼容性。C 最初没有bool
类型,但任何数值表达式都可以用作布尔值(使用 0 ==false
约定)。现在我们陷入了向后兼容性的纠结。nullptr
必须支持惯用构造,例如if(p)
,特别是对于旧代码的文字0
或NULL
被替换为nullptr
的情况。例如,像if(p)
这样的代码可以来自宏扩展或模板代码。
附录:为什么nullptr
不转换为例如int
.
由于nullptr
隐式转换为bool
,而bool
(不幸的是)隐式转换为int
,因此可以预期nullptr
也应该转换为int
。但nullptr
的要点是它应该表现为指针值。虽然指针确实隐式转换为bool
,但它们不会隐式转换为数值类型。
但是,为用户定义类型安排此类限制并不完全简单。如果存在operator bool
转换,将调用转换为int
。一个 C++11 解决方案来预测限制,是使转换运算符成为受std::enable_if
限制的模板,如下所示:
#include <type_traits> // std::enable_if, std::is_same
struct S
{
template< class Type >
operator Type* () const { return 0; }
template<
class Bool_type,
class Enabled = typename std::enable_if<
std::is_same<Bool_type, bool>::value, void
>::type
>
operator Bool_type () const { return false; }
};
auto main() -> int
{
bool const b = S(); // OK.
double const* const p = S(); // OK.
int const i = S(); // !Doesn't compile.
}
C++11 §4.12布尔转换
算术、无作用域枚举、指针或指向成员类型的指针的 prvalue 可以转换为类型
bool
的 prvalue。零值、空指针值或空成员指针值将转换为false
;任何其他值都将转换为true
。std::nullptr_t
类型的 prvalue 可以转换为bool
类型的 prvalue ;结果值为false
。
确实,nullptr
是一个关键字,但它是一个空指针文字,与bool
的角色不同。想想布尔文字,true
和false
也是关键字。
在 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#654 中,杰森·梅里尔认为
我们可以用任意指针做的任何事情,我们也应该能够用nullptr_t做。
我认为以下(有点人为的)示例支持该论点(尽管我不完全确定它是否适用于这种情况)
template<typename T, typename P>
void safeProcess(T pointer, P &processor) {
bool isNonNull(pointer);
if(isNonNull) {
processor.process(pointer);
}
}
这将允许传递nullptr
与processor.process
接受的任何指针兼容的其他指针类型。
C++11 通过引入一个新关键字作为可分辨的空指针常量来更正此问题:nullptr。它属于 nullptr_t 类型,它是隐式可转换的,可与任何指针类型或指向成员的指针类型相媲美。它不是隐式可转换的,也不是与积分类型相当的,除了布尔值。虽然最初的提案指定 nullptr 类型的右值不应转换为布尔值,但核心语言工作组决定,为了与常规指针类型保持一致,这种转换是可取的。2008年6月,对拟议的措辞修改一致表决通过工作文件。[2]
出于向后兼容性的原因,0 仍然是有效的空指针常量。
char *pc = nullptr; // OK
int *pi = nullptr; // OK
bool b = nullptr; // OK. b is false.
int i = nullptr; // error