diff --git a/docs/languages/C&C++/modern_cpp.md b/docs/languages/C&C++/modern_cpp.md index 752ed65d..4f5d9570 100644 --- a/docs/languages/C&C++/modern_cpp.md +++ b/docs/languages/C&C++/modern_cpp.md @@ -9,11 +9,23 @@ title: Modern C++ 选讲 替代 NULL。C++11 引入了 `nullptr` 关键字,专门用来区分空指针、`0`。而 `nullptr` 的类型为 `nullptr_t`,能够隐式的转换为任何指针或成员指针的类型。 ```C++ +void foo(int); +void foo(char*); + foo(0); // 调用 foo(int) -// foo(NULL); // 该行不能通过编译 +// foo(NULL); // 该行在不同编译器下会有不同的行为,可以参考下面的说明。 foo(nullptr); // 调用 foo(char*) ``` +> 在 C++11 之后的标准中,`NULL` 可以是一个整数类型的 0,也可以是一个 `std::nullptr_t`。因此,类似下面的两种编译器实现都是可以的。 +> ```c++ +> #define NULL 0 +> #define NULL nullptr +> ``` +> 在 msvc 中,`NULL` 的实现为 `#define NULL 0`,因此上面的代码是可以通过编译的;而在 gcc 和 clang 中,`NULL` 的实现为 `#define NULL __null`,此处 `__null` 是一个 `long` 类型的 0,同样是符合标准的。 +> +> 因此,对于 `foo(NULL)` 而言,`foo(int)` 和 `foo(char*)` 都不是精确的参数类型匹配,因此不能通过编译(会提示 `foo` 的调用是不明确的);而如果加入 `void foo(long);` 的声明,则 `foo(NULL)` 精确地匹配到了 `foo(long)`,因此可以通过编译。 + ### constexpr 显式声明常量表达式。const 修饰的变量**只在一定情况下**是常量表达式,这有时可能带来困扰。C++11 提供了 `constexpr` 让用户显式的声明函数或对象构造函数**在编译期**会成为常量表达式。 从 C++14 开始,`constexpr` 函数可以在内部使用局部变量、循环和分支等简单语句。