2

考虑一段通用 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_NEnullptr:MSVC++2013 编译器给出error C2593: 'operator <<' is ambiguous.

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

问题的发生是因为nullptr有一个特殊的类型,并且operator <<没有在 STL 中为该类型定义。https://stackoverflow.com/a/21772973/1915854的答案建议定义operator <<std::nullptr_t

//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
}

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

4

2 回答 2

3

这是LWG #2221,它建议:

显而易见的库解决方案是添加一个nullptr_t重载,它的定义类似于

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

我们也可以考虑在核心级别解决这个问题:添加一个特殊情况的语言规则来解决您编写的所有情况f(nullptr)并且f在多个指针类型上重载。(在这种情况下,也许是一个决胜局的说法void*。)

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

于 2015-07-01T15:06:55.953 回答
1

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

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

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

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

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

于 2015-07-01T17:49:21.443 回答