C++ lambda 不推导出函数重载
C++ lambda doesn't deduce function overloading
我正在这样定义 class:
class foo {
public:
// I define const and non-const versions of the 'visit' function
// nb. the lambda is passed by reference
virtual void visitWith(std::function<void(foo&)>&);
virtual void visitWith(std::function<void(const foo&)>&) const;
};
foo 可以有 children 所以我们的想法是递归地访问一个 foo 和它的所有内容 children。
当我尝试使用它时,例如。像这样:
foo f;
f.visitWith([&](const foo&) {
// Do something here
});
我收到编译器错误。编译器不知道该做什么。
我可以通过添加这样的类型转换使其工作:
foo f;
f.visitWith( (std::function<void(const foo&)>) [&](const foo&) {
// Do something here
});
但这太可怕了。
我怎样才能让它正常工作?
编辑:
这可能是 Visual C++ 的问题,它拒绝编译此处给出的代码:
我尝试编译时的VC++输出是:
Edit2:不,Visual C++ 是正确的,代码有歧义。请参阅下面我的解决方案...
lambda 是 compiler-generated 类型,它不是 std::function
的实例,但它可以分配给一个。
您的 visitWith()
方法通过 non-const 引用获取 std::function
,这意味着它需要一个 pre-existing std::function
对象,例如:
std::function<void(const foo&)> func = [&](const foo&) {
// Do something here
};
foo f;
f.visitWith(func);
将 lambda 直接传递给 visitWith()
需要编译器创建临时 std::function
对象,但 non-const 引用不能绑定到临时对象。这就是您的原始代码无法编译的原因。
对于您正在尝试的操作,您必须按值或按 const-reference 传递 std::function
:
class foo {
public:
void visitWith(std::function<void(foo&)>);
void visitWith(std::function<void(const foo&)>) const;
};
class foo {
public:
void visitWith(const std::function<void(foo&)> &);
void visitWith(const std::function<void(const foo&)> &) const;
};
我向 Microsoft 报告了这个“错误”并得到了答复,此处:
简短版:Visual C++ 处理正确,ideone 错误。
最后我通过向 foo 添加第三个重载来解决它,它可以将 const-ness 添加到对象,如下所示:
class foo {
public:
// Use typedefs so that all the code that comes after these two functions is neater
typedef std::function<void(Branch&)>visitor;
typedef std::function<void(const Branch&)>const_visitor;
virtual void visitWith(const visitor&);
virtual void visitWith(const const_visitor&) const;
// This is to thunk the third case that can happen when you start
// a const visit from a non-const foo.
void visitWith(const const_visitor& v) {
static_cast<const foo*>(this)->visitWith(v); // Add const-ness
}
};
现在代码可以工作了,例如:
foo f;
f.visitWith([](const foo& f) {
std::cout << "visited a const foo!" << std::endl;
});
我正在这样定义 class:
class foo {
public:
// I define const and non-const versions of the 'visit' function
// nb. the lambda is passed by reference
virtual void visitWith(std::function<void(foo&)>&);
virtual void visitWith(std::function<void(const foo&)>&) const;
};
foo 可以有 children 所以我们的想法是递归地访问一个 foo 和它的所有内容 children。
当我尝试使用它时,例如。像这样:
foo f;
f.visitWith([&](const foo&) {
// Do something here
});
我收到编译器错误。编译器不知道该做什么。
我可以通过添加这样的类型转换使其工作:
foo f;
f.visitWith( (std::function<void(const foo&)>) [&](const foo&) {
// Do something here
});
但这太可怕了。
我怎样才能让它正常工作?
编辑:
这可能是 Visual C++ 的问题,它拒绝编译此处给出的代码:
我尝试编译时的VC++输出是:
Edit2:不,Visual C++ 是正确的,代码有歧义。请参阅下面我的解决方案...
lambda 是 compiler-generated 类型,它不是 std::function
的实例,但它可以分配给一个。
您的 visitWith()
方法通过 non-const 引用获取 std::function
,这意味着它需要一个 pre-existing std::function
对象,例如:
std::function<void(const foo&)> func = [&](const foo&) {
// Do something here
};
foo f;
f.visitWith(func);
将 lambda 直接传递给 visitWith()
需要编译器创建临时 std::function
对象,但 non-const 引用不能绑定到临时对象。这就是您的原始代码无法编译的原因。
对于您正在尝试的操作,您必须按值或按 const-reference 传递 std::function
:
class foo {
public:
void visitWith(std::function<void(foo&)>);
void visitWith(std::function<void(const foo&)>) const;
};
class foo {
public:
void visitWith(const std::function<void(foo&)> &);
void visitWith(const std::function<void(const foo&)> &) const;
};
我向 Microsoft 报告了这个“错误”并得到了答复,此处:
简短版:Visual C++ 处理正确,ideone 错误。
最后我通过向 foo 添加第三个重载来解决它,它可以将 const-ness 添加到对象,如下所示:
class foo {
public:
// Use typedefs so that all the code that comes after these two functions is neater
typedef std::function<void(Branch&)>visitor;
typedef std::function<void(const Branch&)>const_visitor;
virtual void visitWith(const visitor&);
virtual void visitWith(const const_visitor&) const;
// This is to thunk the third case that can happen when you start
// a const visit from a non-const foo.
void visitWith(const const_visitor& v) {
static_cast<const foo*>(this)->visitWith(v); // Add const-ness
}
};
现在代码可以工作了,例如:
foo f;
f.visitWith([](const foo& f) {
std::cout << "visited a const foo!" << std::endl;
});