"No matching function for call" 创建函数变体向量时出错

"No matching function for call" error when creating a vector of function variants

我正在尝试创建一个 std::vector,它可以使用 std::variant 来容纳 std::function 个不同签名的对象。

为什么以下代码无法编译:

#include <functional>
#include <variant>
#include <vector>

int main()
{
  std::vector<std::variant<
      std::function< int (const std::vector<float>&, int) >,
      std::function< float (const std::vector<float>&, int) >
  >> func_vector;

  func_vector.emplace_back( [] (const std::vector<float>& ret, int index) { return ret.size(); });

  return 0;
}

问题发生在 emplace_back() 期间。编译它会给出一长串错误,列出的第一个错误是:

error: no matching function for call to ‘std::variant<std::function<int(const std::vector<float, std::allocator<float> >&, int)>, std::function<float(const std::vector<float, std::allocator<float> >&, int)> >::variant(main()::<lambda(const std::vector<float>&, int)>)’
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

说找不到匹配的函数,请问具体调用的是什么?

我尝试放置的 lambda 具有我在变体中指定的类型之一的签名,所以一切都应该没问题,不是吗?

emplace_back 应该将 lambda 直接转发给变量初始化。并且有一个转换构造函数可以从任何可转换为成员类型的参数初始化变体的成员。然而,问题是变体的两个成员都可以从这个 lambda 中初始化,从而产生歧义。

是的,您的 lambda 是 std::function< float (const std::vector<float>&, int) > 的有效初始值设定项。这是由于 std::function 执行类型擦除的方式。它将其持有的可调用结果转换为指定的 return 类型。可调用对象只需要能够接受 std::function.

的参数列表

为了说明这一点,如果我们要向 std::function 类型之一添加第三个参数,

std::vector<std::variant<
  std::function< int (const std::vector<float>&, int) >,
  std::function< float (const std::vector<float>&, int, int) >
>> func_vector;

然后would be no ambiguity。 lambda 现在只有一个变体成员是有效的初始值设定项。

解决方法是转换为您希望保留的确切函数类型,或者告诉放置的变体它应该初始化哪个选项,例如:

func_vector.emplace_back( std::in_place_index<0>, [] (const std::vector<float>& ret, int ) { return ret.size(); });

std::variant 的转换构造函数的行为类似于重载决策,以确定要构造的类型。

如果你有两个函数

void f(std::function< int (const std::vector<float>&, int) >);
void f(sstd::function< float (const std::vector<float>&, int) >);

然后打电话

f([] (const std::vector<float>& ret, int index) { return ret.size(); })

也会有歧义,因为如果参数是 callable 且类型为 const std::vector<float>& 和 [=15],则 std::function 的构造函数会参与重载决策=] 和 return 类型可隐式转换为 intfloat。类型不需要完全相同。

因此,对于您的 lambda,两种重载都是可能的,并且由于它们中的每一种都需要一个用户定义的转换(从 lambda 类型到 std::function),所以重载解析是不明确的。