我正在将一些旧代码从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;
}
答案 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
类型的参数进行调用。在您的情况下,pointer
为D*
。你的删除器不能用这个来调用,而是需要一个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编译器,有些可能实际上能够编译上面的,但我没有他们躺在身边。)