尽管明确说明了返回类型,但对lambda的调用还是模棱两可的


11

鉴于lambda的类型是可确定的(可强制转换为a std::function(请纠正我,如果我错了,请纠正我)),重载函数应该同时使用两个函子。已定义?([&]() -> 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;
      }
   );
}

6
因为std::function<void(int)>甚至可以从返回某些内容的lambda构造出(因为这会导致返回值被忽略)。
HolyBlackCat

1
顺便说一句,显式指定该lambda的return-type完全不起作用。
Deduplicator

Answers:


8

由于第二个lambda表达式返回bool可以转换到两个std::function<void(int)>std::function<bool(int)>含蓄。

std::function 有一个转换构造函数:

template< class F >
function( F f );

除非参数类型为Args ...且返回类型为R的f可调用,否则此构造方法不参与重载解析。(从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 returning 是有效的表达式(返回的结果只是转换为)。然后,它也可能隐式转换并引起歧义问题。std::function<void(int)>static_cast<void>(INVOKE(f, t1, t2, ..., tN))boolvoidstd::function<void(int)>


6

您可以static_cast将lambda 显式指定为正确的类型

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 建议的那样,随时随地std::function<bool(int)>从lambda 构造

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

您可以跳过static_caststd::function直接从中构造一个。无论如何,这就是在隐式转换期间发生的所有事情。
Max Langhof

我的观点是,您可以从字面上仅除去static_cast<和last >,它将执行相同的操作,但键入的次数较少。它不需要更多的行或任何东西。godbolt.org/z/fQTqF4
Max Langhof
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.