我正在尝试创建一个可以使用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
的构造函数参与重载解析,并返回类型隐式转换为int
或float
。类型不需要完全相同。
因此,您的 lambda 可以同时使用这两种重载,并且由于它们中的每一个都需要一次用户定义的转换(从 lambda 类型到std::function
(,因此重载分辨率不明确。