`const std::string& s = nullptr` 如何作为可选参数工作

How `const std::string& s = nullptr` works as an optional parameter

据我所知,引用不能为空,但是当我 运行 代码如下时:

#include <iostream>
#include <string>

void test(int i, const std::string& s = nullptr) {
  std::cout << i << " " << s << std::endl;
}

int main() {
  test(1, "test");
  test(2);
}

可选参数s可以为空,构建代码。更重要的是,当 test(2) 运行 时,程序会抛出异常,而不是打印一些随机字符串。

当我将 s 更改为一些基本类型(如 int)时,它无法编译,所以我认为魔术留在字符串 class 中,但是如何呢?

此外,我如何检查 s 是否为空?如果我使用 if(s==nullptr)if(s.empty()),它编译失败。

test 使用 std::basic_string<char>:

的构造函数 number 5 初始化了它的参数
basic_string( const CharT* s,
              const Allocator& alloc = Allocator() );

因为它需要具体化一个临时 (std::string) 来绑定到该引用。这是因为引用必须绑定到正确类型的对象,而 std::nullptr_t 不是。并且所述构造函数对传递的指针具有 not null 约束。在没有显式参数的情况下调用 test 会导致未定义的行为。

非常清楚,在格式良好的 C++ 程序中没有空引用这样的东西。引用必须绑定到 有效对象 。尝试用 nullptr 初始化一个只会寻求进行转换。

由于std::string是一个具有明确"empty"状态的对象,固定版本可以简单地传入一个默认的初始化字符串:

void test(int i, const std::string& s = {}); // Empty string by default.

一旦违反合同的问题得到解决,s.empty() 应该会再次给出有意义的结果。

Reference 确实不能为 null,但是 const std::string& s = nulltr 并不像您认为的那样。当未指定第二个参数时,编译器将创建一个字符串对象,调用 implicit 字符串构造函数,该构造函数将指向以 null 结尾的字符串的指针作为第一个参数。所以 test(2); 调用看起来像这样:

test(2, ::std::string(static_cast<char const *>(nullptr), ::std::string::allocator_type()));

请注意,将 nullptr 作为第一个参数传递会导致未定义的行为。