vc2013与2015中的Lambda删除器

Lambda Deleter in VC 2013 vs 2015

本文关键字:删除 Lambda 中的 2015 vc2013      更新时间:2023-10-16

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

删除器的类型必须可以用pointer类型的参数调用。在你的例子中,pointerD*。您的deleter不能用this调用,而是需要一个类型为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编译器,有些可能实际上能够编译上面的代码,但我没有把它们放在周围)

如果我没有错,问题是您将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编译?"