无法使用各种 lambda 表达式初始化 std::variant
Cannot initialize std::variant with various lambda expressions
我正在玩 std::variant, lambdas
和 std::future
,当我试图将它们组合在一起时得到了非常奇怪的结果。以下是示例:
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?
这里是编译错误:
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
:
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>
如此特别?
variant
的转换构造函数模板使用重载决策来确定构造对象应具有的类型。特别是,这意味着如果对这些类型的转换同样好,则构造函数不起作用;在您的情况下,如果 std::function
专业之一可以从您的论点中构造出来,它就可以工作。
那么什么时候 function<...>
可以从给定的论证中构造出来?从 C++14 开始,如果参数可使用参数类型调用并生成 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
的类型。如果你有一个 function
returning void
,你传入的仿函数可以 return 任何东西——这是一个特性,而不是一个错误!这也是为什么function<void(int)>
适用于f1
的原因。另一方面,future<int>
不会转换为 future<void>
;因此只有 function<void(int)>
是可行的,变体的索引是 1.
然而,在第二种情况下,lambda returns future<void>
可转换为 future<void>
和 void
。如上所述,这导致两个 function
专精都可行,这就是 variant
无法决定构建哪个的原因。
最后,如果将 return 类型调整为 int
,整个 void
转换问题就可以避免,所以一切都按预期进行。
我正在玩 std::variant, lambdas
和 std::future
,当我试图将它们组合在一起时得到了非常奇怪的结果。以下是示例:
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?
这里是编译错误:
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
:
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>
如此特别?
variant
的转换构造函数模板使用重载决策来确定构造对象应具有的类型。特别是,这意味着如果对这些类型的转换同样好,则构造函数不起作用;在您的情况下,如果 std::function
专业之一可以从您的论点中构造出来,它就可以工作。
那么什么时候 function<...>
可以从给定的论证中构造出来?从 C++14 开始,如果参数可使用参数类型调用并生成 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
的类型。如果你有一个 function
returning void
,你传入的仿函数可以 return 任何东西——这是一个特性,而不是一个错误!这也是为什么function<void(int)>
适用于f1
的原因。另一方面,future<int>
不会转换为 future<void>
;因此只有 function<void(int)>
是可行的,变体的索引是 1.
然而,在第二种情况下,lambda returns future<void>
可转换为 future<void>
和 void
。如上所述,这导致两个 function
专精都可行,这就是 variant
无法决定构建哪个的原因。
最后,如果将 return 类型调整为 int
,整个 void
转换问题就可以避免,所以一切都按预期进行。