尽管显式说明了返回类型,但对lambda的调用仍然不明确

时间:2019-10-30 14:02:13

标签: c++ c++11 lambda implicit-conversion std-function

鉴于lambda的类型是可确定的(可转换为std::function(如果我错了,请纠正我),重载函数应该同时使用两个函子。 问题是:尽管明确定义了lambda类型,为什么下面仍会出现编译错误? ([&]() -> Type {}

请注意,对于我当前的解决方案,我需要按引用捕获, 这就是代码包含其逻辑的原因。

以下示例描述了问题:

#include <iostream>
#include <string>    
#include <functional>

void do_some(std::function<void(int)> thing) 
{
   thing(5);
}

void do_some(std::function<bool(int)> thing)
{
   if (thing(10)) 
   {
      std::cout << "it's true!" << std::endl;
   }
}

int main()
{
   int local_to_be_modified = 0;
   do_some(
      [&](int in)
      {
         local_to_be_modified = in;
         std::cout << "This is void-" << std::endl;
      }
   );
   do_some(
      [&](int in) -> bool
      { 
         // error: call to 'do_some' is ambiguous
         local_to_be_modified += in;
         std::cout << "This is bool-" << std::endl;
         return true;
      }
   );
}

2 个答案:

答案 0 :(得分:8)

因为第二个lambda表达式返回bool可以隐式转换为std::function<void(int)>std::function<bool(int)>

std::function具有转换构造函数:

template< class F >
function( F f );
     

除非参数类型为Args的f为 Callable ,并且返回类型R,此构造函数不参与重载解析(自C ++ 14起)

作为Callable的定义,

  

以下表达式必须有效:

INVOKE<R>(f, std::declval<ArgTypes>()...)
     

其中 INVOKE(f,t1,t2,...,tN)定义为   static_cast<void>(INVOKE(f, t1, t2, ..., tN)),如果R可能是   cv合格的void,否则为 INVOKE(f,t1,t2,...,tN)隐式   转换为R

请注意,对于bool,第二个lambda返回std::function<void(int)>,如上所示,static_cast<void>(INVOKE(f, t1, t2, ..., tN))是有效的表达式(返回的bool只是转换为{{ 1}})。然后它也可能隐式转换为void并引起歧义问题。

答案 1 :(得分:6)

您可以将lambda明确static_cast设置为正确的类型

using FunBoolRet = std::function<bool(int)>;

do_some(static_cast<FunBoolRet >([&](int in) 
   {
      local_to_be_modified += in;
      std::cout << "This is bool-" << std::endl;
      return true;
   }));

或将lambda存储为正确的std::function<bool(int)>类型并传递给函数(如果do_some(lmda)应该被多次调用)

FunBoolRet lmda = [&](int in)
{
    local_to_be_modified += in;
    std::cout << "This is bool-" << std::endl;
    return true;
};    
do_some(lmda); // pass the lambda

或按照 @MaxLanghof 的建议 只需随时随地从lambda构造std::function<bool(int)>

do_some(FunBoolRet{
   [&](int in) 
   {
      local_to_be_modified += in;
      std::cout << "This is bool-" << std::endl;
      return true;
   }
});