7

我正在尝试将我的项目从 Visual Studio 2010 移植到 Visual Studio 2012。在我的代码中,我有一些如下所示的文件处理:

auto fileDeleter = [](FILE* f) { fclose(f); };

unique_ptr<FILE, decltype(fileDeleter)> fMinute(
    fopen(minuteLogName.c_str(), "w"), fileDeleter);


unique_ptr<FILE, decltype(fileDeleter)> fIndividual(
    fopen(individualLogName.c_str(), "w"), fileDeleter);

if (!fMinute || !fIndividual) {
    throw Exceptions::IOException("One of the log files failed to open",
                                  __FUNCTION__);
}

这在 2010 年没有任何问题,但在 2012 年,它在以下条件下失败:

错误 C2678:二进制“!” : 未找到采用左手操作数类型 > 'std::unique_ptr<_Ty,_Dx>' 的运算符(或没有可接受的转换)
...
可能是 'built-in C++ operator!(bool)'

C++11 标准规定unique_ptr 有一个 bool 运算符,允许您像上面那样进行快速检查。更奇怪的是,VS2012 的 unique_ptr 定义有这个运算符:

_OPERATOR_BOOL() const _NOEXCEPT
{   // test for non-null pointer
    return (this->_Myptr != pointer() ? _CONVERTIBLE_TO_TRUE : 0);
}

但是我在编译时得到了那个错误。为什么?

是的,我可以只是使用ofstream,但那不是重点。

4

3 回答 3

6

为了建立 BigBoss 所说的,C++11 需要std::unique_ptruse explicit operator bool() noexcept,它解决了整个隐式转换为 bool 的问题。除了... VC2012 还不支持 explicit运算符。因此,他们必须使用安全布尔成语

虽然 safe-bool 习惯用法很好,但它可能存在缺陷(这就是explicit operator bool()存在的原因),具体取决于您如何实现该习惯用法。您显然在 VC2012 中遇到了其中之一。使用 重新配置您的测试!(fMinute && fIndividual)应该可以解决它。

但无论哪种方式,它都是一个 Visual Studio 错误。由于行为发生了变化,即使您设法找到解决方法,您也应该提交错误报告。

于 2012-10-20T23:41:37.517 回答
1

您可以使用if (!(fMinute && fIndividual) )而不是if (!fMinute || !fIndividual). C++ 说它们可以转换为 bool,但operator bool通常会产生问题,例如你可能有一个接受的函数int,如果你的类有一个operator bool然后它可以转换为 int,你可以将它传递给这个函数,但例如在我们的例子中unique_ptr从未打算用作int,因此许多开发人员从不operator bool直接使用,而是编写了一个可以在条件表达式中用作 bool 的运算符,但它实际上不是 bool!

struct bool_convertible {
    typedef void (*convertible_to_bool)();
    static void convertible_to_true();
    operator convertible_to_bool () const {
        return test() ? &convertible_to_true : nullptr;
    }
};

使用这种技术我可能有bool_convertible c; if( c ) {...}但我不能

void test_int( int );
bool_convertible c;
test_int( c );
于 2012-10-20T23:29:14.747 回答
1

在最近的 C++11 标准中,std::unique_ptr 没有operator!定义,只有显式转换运算符

explicit operator bool() const;

但是,内置的一元逻辑否定运算符 ,!根据 5.3.1/9 上下文将其参数转换为 bool:

逻辑否定运算符的操作数根据!上下文转换为bool(第 4 条);如果转换的操作数为假,则其值为真,否则为假

到 bool 的上下文转换将使用显式转换运算符(如果可用)。因此,您的代码实际上应该在 C++11 规则下工作。您可能应该向 Microsoft 提交错误报告。它们是否支持显式转换运算符无关紧要。

作为一种解决方法,试试这个:

if (!fMinute.get() || !fIndividual.get()) {
    ....
于 2012-10-20T23:50:18.990 回答