无法使用各种Lambda表达式初始化std :: variant [英] Cannot initialize std::variant with various lambda expressions

查看:104
本文介绍了无法使用各种Lambda表达式初始化std :: variant的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在玩std::variant, lambdasstd::future,当我尝试将它们组合在一起时得到了超级奇怪的结果.以下是示例:

I'm playing with std::variant, lambdas and std::future, and got super weird results when I tried to compose them together. Here are examples:

using variant_t = std::variant<
    std::function<std::future<void>(int)>,
    std::function<void(int)>
>;
auto f1 = [](int) { return std::async([] { return 1; }); };
auto f2 = [](int) { return std::async([] {  }); };

variant_t v1(std::move(f1)); // !!! why DOES this one compile when it SHOULDN'T?
auto idx1 = v1.index(); //equals 1. WHY?

variant_t v2(std::move(f2)); // !!! why DOESN'T this one compile when it SHOULD?

这是编译错误:

错误C2665'std :: variant< std :: function< std :: future< void> (int)>,std :: function< void(int)>> :: variant':2个重载都不 可以转换所有参数类型

Error C2665 'std::variant<std::function<std::future<void> (int)>,std::function<void (int)>>::variant': none of the 2 overloads could convert all the argument types

好,让我们将variant的项目签名从void返回到int:

OK, lets change variant's items signatures from returning void to int:

using variant_t = std::variant<
    std::function<std::future<int>(int)>,
    std::function<int(int)>
>;

variant_t v1(std::move(f1)); // COMPILES (like it should)
auto idx1 = v1.index(); // equals 0

variant_t v2(std::move(f2)); // DOESN'T compile (like it should)

这到底是怎么回事?为什么std::future<void>如此特别?

What the hell is going on here? Why is std::future<void> so special?

推荐答案

variant的转换构造函数模板使用重载分辨率来确定所构造的对象应具有的类型.特别是,这意味着,如果对这些类型的转换同样出色,则构造函数将无法工作.在您的情况下,如果完全可以根据您的论证构造std::function专业化之一,它就可以工作.

variant's converting constructor template employs overload resolution to determine which type the constructed object should have. In particular, this means that if the conversions to those types are equally good, the constructor doesn't work; in your case, it works iff exactly one of the std::function specializations is constructible from your argument.

那么什么时候function<...>可以从给定的参数构造出来?从C ++ 14开始,如果参数可以使用参数类型调用,并且产生的类型为可转换为返回类型.请注意,根据此规范,如果返回类型为void,则任何操作都会进行(如

So when is function<...> constructible from a given argument? As of C++14, if the argument is callable with the parameter types and yields a type that is convertible to the return type. Note that according to this specification, if the return type is void, anything goes (as any expression can be converted to void with static_cast). If you have a function returning void, the functor you pass in can return anything—that's a feature, not a bug! This is also why function<void(int)> is applicable for f1. On the other hand, future<int> does not convert to future<void>; hence only function<void(int)> is viable, and the variant's index is 1.

但是,在第二种情况下,lambda返回future<void>,它可以转换为future<void>void.如上所述,这使得function的两个专业都可行,这就是variant无法确定要构建哪个专业的原因.

However, in the second case, the lambda returns future<void>, which is convertible to both future<void> and void. As mentioned above, this causes both function specializations to be viable, which is why the variant cannot decide which one to construct.

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

Finally, if you adjust the return type to int, this whole void conversion issue is avoided, so everything works as expected.

这篇关于无法使用各种Lambda表达式初始化std :: variant的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆