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++ 的问题,它拒绝编译此处给出的代码:

https://ideone.com/n9bySW

我尝试编译时的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;
};

Live Demo

class foo {
public:
    void visitWith(const std::function<void(foo&)> &);
    void visitWith(const std::function<void(const foo&)> &) const;
};

Live Demo

我向 Microsoft 报告了这个“错误”并得到了答复,此处:

https://developercommunity.visualstudio.com/content/problem/1201858/c-stdfunction-overloading-fails.html

简短版: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;
});