我正在尝试创建一个std::vector
,它可以使用std::function
容纳不同签名的std::variant
个对象。
为什么以下代码无法编译:
#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完全具有我在变体中指定的一种类型的签名,所以一切都很好,不是吗?
答案 0 :(得分:4)
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;
然后在那里would be no ambiguity。 lambda是目前仅适用于一个变体成员的有效初始化程序。
解决方法是将其强制转换为您希望保留的确切函数类型,或者告诉放置的变体应初始化的选项,例如:
func_vector.emplace_back( std::in_place_index<0>, [] (const std::vector<float>& ret, int ) { return ret.size(); });
答案 1 :(得分:2)
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(); })
也将是模棱两可的,因为如果参数是类型为std::function
和const std::vector<float>&
且返回类型为 callable 的int
的构造方法将参与重载解析隐式转换为int
或float
。类型不必完全相同。
因此,对于您的lambda来说,这两种重载都是可能的,并且由于每个重载都需要一个用户定义的转换(从lambda类型转换为std::function
),因此重载分辨率是不确定的。