【问题标题】:Lambda Deleter in VC 2013 vs 2015VC 2013 与 2015 中的 Lambda 删除器
【发布时间】:2016-12-23 04:00:21
【问题描述】:

我正在将一些旧代码从 VC 2013 移动到 2015。

下面的简化代码在 VC 2013 中运行良好,但在 2015 年失败:

error C2664: 'void main::<lambda_da721648e605a5fd45c9a3fb8c3d06f6>::operator ()(main::D *&) const': cannot convert argument 1 from 'main::D *' to 'main::D *&'

我不是在寻找解决方案,而是在寻找改变的原因和原因。


谢谢。

#include <memory>

int main()
{
  class D{};

  auto mydel = []( D*&p ) { delete p; p = 0; };

  std::unique_ptr< D, decltype(mydel) > up( new D );

  return 0;
}

【问题讨论】:

  • 显然unique_ptr 的内部结构过去总是使用左值pointer 调用删除器,但现在至少使用右值pointer 调用它一次。
  • 您确定在两个版本中使用相同的设置吗?这可能与 MSVC 臭名昭著的扩展有关,该扩展允许将右值绑定到非 const 左值引用。也许他们在 VS2015 中默认禁用此功能?
  • @Praetorian 我对两个版本都使用默认设置。我不知道如何更改此选项。
  • @ZDF 你可以在Project Properties -&gt; C/C++ -&gt; Language -&gt; Disable Language Extensions改一下
  • @Rakete1111 关/开没有区别。

标签: c++ c++11 visual-studio-2013 lambda visual-studio-2015


【解决方案1】:

删除器的类型必须可以使用pointer 类型的参数调用。在您的情况下,pointerD*。你的删除器不能用这个来调用,而是需要一个pointer&amp;类型的参数,所以你的代码格式不正确,不需要诊断。

另外,decltype(mydel) 是一个 lambda 对象类型。 Lambda 对象没有默认构造函数,即使是无状态构造函数。您的唯一指针创建代码:

std::unique_ptr< D, decltype(mydel) > up( new D );

因此格式不正确。正确的版本是:

std::unique_ptr< D, decltype(mydel) > up( new D, mydel );

这很烦人。

奇怪的是 2013 年的 lambda 有一个零参数构造函数,违反了标准。 MSVC2013 只是名义上的 C++11 编译器。

另外,它可能只传入了左值D* 类型。允许这样做,但标准不要求这样做。


虽然这不是您问题的重点,但我会注意到我们可以在 C++17 中按如下方式进行清理:

template<auto* pfunc>
struct stateless {
  template<class...Args>
  decltype(auto) operator()(Args&&...args)const {
    return std::invoke( pfunc, std::forward<Args>(args)... );
  }
};

int main() {
  class D{};

  auto mydel = []( D*p ) { delete p; };

  std::unique_ptr< D, stateless<+mydel> > up( new D );

  return 0;
}

但 MSVC2015 不支持此功能(如果您在以后的更新中请求最新标准,则可能)。

C++17 代码未在 C++17 编译器上测试,因为实际上还没有(有一些 C++1z 编译器,有些可能实际上能够编译上述代码,但我没有他们躺在周围。)

【讨论】:

    【解决方案2】:

    如果我没记错的话,问题是您将up 声明为std:unique_ptr,并带有decltype(mydel) 类型的删除器,但您没有将mydel 传递给它。

    正确的调用应该是

    std::unique_ptr< D, decltype(mydel) > up( new D, mydel );
    

    根据cppreference,你的构造函数

    要求 Deleter 是 DefaultConstructible 并且该构造 不会抛出异常。

    而且,如果我没记错的话,decltype(mydel) 不是默认可构造的(怎么可能?)

    我想,正确的问题不是“为什么 VC 2015 会出错?”但是“为什么 VC 2013 编译?”

    【讨论】:

    • 你仍然会得到同样的错误。我不是在寻找解决方案,而是在寻找解释(我已经修复了代码)。我怀疑解释与标准的“更好”实施有关。我自己没那么聪明。
    • @ZDF 如果不传入 lambda,您的代码不符合标准,因为 mydel 应该没有默认构造函数。也可能存在其他问题,但这确实回答了为什么您的代码以前格式错误,而新编译器拒绝它是正确的。
    • @Yakk,我同意。但是为什么2013年没有问题呢?
    • @ZDF 编译器错误可能:)
    • @ZDF - 修改了我的答案,试图回答你的问题(但 Yakk 更清楚)。
    猜你喜欢
    • 1970-01-01
    • 2018-07-29
    • 2016-11-06
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    • 2016-02-29
    • 2015-09-24
    • 1970-01-01
    相关资源
    最近更新 更多