nullptr 的运算符 <<(流输出)

operator << (stream output) for nullptr

考虑一段通用的 C++ 代码,它向流输出其参数值,以防它们不相等:

#define LOG_IF_NE(a, b) if(a != b) { \
    std::cerr << "Failed because (" << ##a << "=" << (a) << \
        ") != (" << ##b << "=" << (b) << ")"; \
}

这只是一个示例,实际代码在将消息写入字符串流后抛出异常。 这适用于定义流 operator << 的 2 个整数、2 个指针等。

int g_b;
int f(int a)
{
    LOG_IF_NE(a, g_b);
    // implementation follows
}

LOG_IF_NE 的参数之一是 nullptr 时出现问题:MSVC++2013 编译器给出 error C2593: 'operator <<' is ambiguous

int *pA;
int g()
{
    LOG_IF_NE(pA, nullptr);
}

问题的发生是因为 nullptr 有一个特殊的类型,而 operator << 没有在该类型的 STL 中定义。 的答案建议为 std::nullptr_t

定义 operator <<
//cerr is of type std::ostream, and nullptr is of type std::nullptr_t
std::ostream& operator << (std::ostream& os, std::nullptr_t)
{
    return os << "nullptr"; //whatever you want nullptr to show up as in the console
}

这是解决问题的正确方法吗? operator<< 没有为 nullptr_t 定义,这不是 C++11/STL 中的错误吗? C++14/17 是否需要修复?或者它是故意的(因此一个人对 operator<< 的私人定义可能有陷阱)?

这是LWG #2221,建议:

The obvious library solution is to add a nullptr_toverload, which would be defined something like

template<class C, class T>
basic_ostream<C, T>& operator<<(basic_ostream<C, T>& os, nullptr_t) 
{ 
  return os << (void*) nullptr; 
}

We might also consider addressing this at a core level: add a special-case language rule that addresses all cases where you write f(nullptr) and f is overloaded on multiple pointer types. (Perhaps a tiebreaker saying that void* is preferred in such cases.)

它不在 C++14 中,我不知道它是否会进入 C++17。这是一个非常容易解决的问题,因此就标准更改而言,它的优先级不是特别高。正如您在问题中所说的那样 - 它只是一个 3 行函数。

我认为这可能是故意的,原因与 nullptr 是它自己的价值相同。在这种情况下默默地接受它可能会被视为违反前提条件和不变量。

A nullptr 是一个初始化指针的值,以检测它是否未被初始化。因此,按照这种逻辑,无论如何实际使用它都应该是明确的并记录在案,以防止滥用和潜在的安全漏洞。简单地重载运算符以无论如何打印出来都不会提供这个。

在调试环境中(您的宏将在这里调用)使用带条件编译的断言更有意义,如果您正在检查不变量和程序逻辑以及关于其他所有内容的定义明确的输出。

这基本上可以归结为一个设计点:在可以最好地从中恢复错误的地方处理错误。您的宏测试是否存在不平等,但如果它发现 nullptr 则该宏处理该错误没有意义,因此返回异常处理更有意义,因此可以将问题抛出到可以处理和处理的地方从 nullptr 恢复。否则您将允许程序处于不一致或不安全的状态。

编辑: 刚刚看到您实际上正在使用异常处理。嵌套的 try/catch 可能是最佳选择,因为您可以在可以处理的地方捕获这两个错误。