我不明白为什么下面的代码会编译?
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 的解决方案是使转换运算符成为模板,受 a 限制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布尔转换
算术、无作用域枚举、指针或指向成员类型的指针的纯右值可以转换为类型的纯右值
bool
。零值、空指针值或空成员指针值转换为false
; 任何其他值都转换为true
. 类型的纯右值std::nullptr_t
可以转换为类型的纯右值bool
;结果值为false
。
确实nullptr
是关键字,但它是一个空指针字面量,与bool
. 想想布尔文字,true
也是false
关键字。
在http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#654中,Jason Merril 认为
我们可以用任意指针做的任何事情,我们也应该可以用 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 类型,可隐式转换并与任何指针类型或指向成员的指针类型相当。除了 bool 之外,它不能隐式转换或与整数类型相比较。虽然最初的提案规定 nullptr 类型的右值不应转换为 bool,但核心语言工作组认为这种转换是可取的,以与常规指针类型保持一致。拟议的措辞更改于 2008 年 6 月被一致投票纳入工作文件。 [2]
出于向后兼容的原因,0 仍然是一个有效的空指针常量。
char *pc = nullptr; // OK
int *pi = nullptr; // OK
bool b = nullptr; // OK. b is false.
int i = nullptr; // error