C++ 无法使用各种lambda表达式初始化std::variant

C++ 无法使用各种lambda表达式初始化std::variant,c++,lambda,future,c++17,variant,C++,Lambda,Future,C++17,Variant,我正在玩std::variant、lambdas和std::future,当我试图将它们组合在一起时,得到了非常奇怪的结果。以下是一些例子: 使用variant\u t=std::variant< std::函数, std::函数 >; auto f1=[](int){return std::async([]{return 1;});}; 自动f2=[](int){return std::async([]{});}; 变体v1(标准::移动(f1));/!!!为什么这一个不应该编译呢? auto

我正在玩
std::variant、lambdas
std::future
,当我试图将它们组合在一起时,得到了非常奇怪的结果。以下是一些例子:

使用variant\u t=std::variant<
std::函数,
std::函数
>;
auto f1=[](int){return std::async([]{return 1;});};
自动f2=[](int){return std::async([]{});};
变体v1(标准::移动(f1));/!!!为什么这一个不应该编译呢?
auto idx1=v1.index()//等于1。为什么?
变型2(标准::移动(f2));/!!!为什么这个不在应该编译的时候编译呢?
以下是编译错误:

错误C2665'std::variant::variant':两个重载都没有 无法转换所有参数类型

好的,让我们将
variant
的项目签名从返回
void
更改为
int

使用variant\u t=std::variant<
std::函数,
std::函数
>;
变体v1(标准::移动(f1));//编译(就像它应该做的那样)
auto idx1=v1.index();//等于0
变体v2(标准::移动(f2));//不编译(就像它应该编译的那样)

这到底是怎么回事?为什么
std::future
如此特殊

variant
的转换构造函数模板使用重载解析来确定构造对象应具有的类型。特别是,这意味着如果对这些类型的转换同样好,那么构造函数就不能工作;在您的例子中,如果可以从您的参数构造一个
std::function
专门化,那么它就可以工作

那么什么时候可以从给定的参数构造
函数
?从C++14开始,如果参数可以使用参数类型调用,并且生成的类型为。请注意,根据本规范,如果返回类型为
void
,则任何内容都会变为(as)。如果您有一个
函数
返回
void
,那么您传入的functor可以返回任何特性,而不是bug!这也是为什么
函数
适用于
f1
。另一方面,
future
不会转换为
future
;因此,只有
函数
是可行的,变量的索引是1

但是,在第二种情况下,lambda返回
future
,可转换为
future
void
。如上所述,这使得
函数
专门化都是可行的,这就是
变量
无法决定构造哪一个的原因


最后,如果您将返回类型调整为
int
,则整个
void
转换问题将被避免,因此一切都按预期进行

注意:
std::variant
是C++17的一项功能,而不是C++11。您的编译错误来自第二个示例,但您的问题使它看起来像是来自第一个示例。谢谢您的回答。但我仍然无法想象
std::future
如何隐式转换为
void
(或者
void
转换为
std::future
——我不确定我是否理解这一点)?这是否意味着所有内容都可以转换为
void
?@DmitryKatkevich这是正确的,任何表达式都可以通过
static\u cast
转换为
void
。否则,我们无法向
函数提供当
函数
产生
void
时返回某些内容的函子,这是所需的特性!