从 Visual Studio 2010 迁移到 2012 时的 C++11 问题

Posted

技术标签:

【中文标题】从 Visual Studio 2010 迁移到 2012 时的 C++11 问题【英文标题】:C++11 issues when moving from Visual Studio 2010 to 2012 【发布时间】:2012-10-20 22:42:50 【问题描述】:

我正在尝试将我的项目从 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>' 的运算符(或没有可接受的转换) ... 可能是“内置 C++ 运算符!(布尔)”

C++11 标准指定unique_ptr has a bool operator 允许您像我上面那样进行快速检查。更奇怪的是,VS2012 的 unique_ptr 定义有这个操作符:

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

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

是的,我可以改用ofstream,但这不是重点。

【问题讨论】:

这似乎是由于使用 lambda 作为自定义删除器造成的。如果您使用其他东西,例如一个普通的函数对象,那么就没有问题了。 【参考方案1】:

为了建立在 BigBoss 所说的基础上,C++11 要求 std::unique_ptr 使用 explicit operator bool() noexcept,这解决了整个隐式转换为 bool 的问题。除了... VC2012 还不支持 explicit 运算符。因此,他们必须使用safe-bool idiom。

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

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

【讨论】:

VS2012也不支持noexcept【参考方案2】:

您可以使用if (!(fMinute &amp;&amp; fIndividual) ) 代替if (!fMinute || !fIndividual)。 C++ 说它们可以转换为 bool,但 operator bool 通常会产生问题,例如,您可能有一个接受 int 的函数,如果您的类有一个 operator bool,那么它可以转换为 int,您可以将其传递给这个函数,但例如在我们的例子中,unique_ptr 从未打算用作int,因此许多开发人员从不直接使用operator 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 );

【讨论】:

std::unique_ptr 的特化不能转换为bool。但是,它们可以上下文通过使用explicit 转换运算符转换为boolbool @LucDanton:技术上是正确的,但这并没有改变,因为“!”是可以在上下文中转换为 bool 的上下文之一。 @NicolBolas 这不会让这个答案变得更有用。【参考方案3】:

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

explicit operator bool() const;

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

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

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

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

if (!fMinute.get() || !fIndividual.get()) 
    ....

【讨论】:

以上是关于从 Visual Studio 2010 迁移到 2012 时的 C++11 问题的主要内容,如果未能解决你的问题,请参考以下文章

ASP.Net - 从 Visual Studio 2003 过渡到 Visual Studio 2010

从 Visual Studio 2005 迁移到 2008 和 .NET 2.0

迁移的 Visual Studio 项目未找到 NuGet 包

从 Visual Studio 2008 迁移到 2015

在 Visual Studio 2010 中使用 .Net 2.0 Web 参考

从 Visual Studio 2008 升级到 Visual Studio 2010 速成版