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



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

为什么下面的代码不编译:

#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执行类型擦除的方式造成的。它将所持有的可调用对象的结果强制转换为指定它的返回类型。可调用对象只需要能够接受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;

那么就不会有歧义了。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(); })

也会模棱两可,因为如果参数可以使用类型const std::vector<float>&int调用,则std::function的构造函数参与重载解析,并返回类型隐式转换为intfloat。类型不需要完全相同。

因此,您的 lambda 可以同时使用这两种重载,并且由于它们中的每一个都需要一次用户定义的转换(从 lambda 类型到std::function(,因此重载分辨率不明确。

相关内容

最新更新