2013年VC与2015年的Lambda Deleter

时间:2016-08-16 17:03:09

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

我正在将一些旧代码从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;
}

2 个答案:

答案 0 :(得分:4)

如果我没错,问题是您将up声明为std:unique_ptr,其删除类型为decltype(mydel),但您未将mydel传递给std::unique_ptr< D, decltype(mydel) > up( new D, mydel );

正确的电话应该是

decltype(mydel)

根据cppreference,您的构造函数

  

要求Deleter是DefaultConstructible和那个构造   不会抛出异常。

并且,如果我没有错,{{1}}不是默认的可构造的(它怎么可能?)

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

答案 1 :(得分:4)

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

此外,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编译器,有些可能实际上能够编译上面的,但我没有他们躺在身边。)