std::transform搭配std::variant时lambda返回类型推导失败解决方法
问题背景
现有两个vector容器:
- 一个存储具备类联合体特性的第三方类型
baz实例,可通过其提供的接口获取内部实际存储的对应类型数据 - 另一个存储由自定义类型
foo、bar组成的std::variant<bar,foo>类型实例
期望使用std::transform批量将baz元素转换为目标variant类型,但编译阶段报错,提示传入std::transform的lambda表达式无法自动推导返回类型,可复现问题的示例代码如下:
#include <variant> #include <vector> #include <algorithm> #include <stdexcept> // third party types struct fooData {}; struct barData {}; struct baz { int foo_or_bar; fooData f; barData b; fooData* asFoo() { return &f; } barData* asBar() { return &b; } }; //my types struct bar { }; struct foo { }; //converter struct converter { bar operator()(const barData& b) { return bar{}; } foo operator()(const fooData& f) { return foo{}; } }; int main() { using entry = std::variant<bar,foo>;; //vector of third party type std::vector<baz> bazzs{}; //vector of my variant type std::vector<entry> target{}; std::transform(bazzs.begin(),bazzs.end(),std::back_inserter(target), [](baz& bazzer){ //both foo and bar are part of the variant, but it refuses to compile switch(bazzer.foo_or_bar) { case 0: return converter{}(*(bazzer.asBar())); case 1: return converter{}(*(bazzer.asFoo())); default: throw std::runtime_error("ERROR"); } }); }
报错原因
C++ lambda的自动返回类型推导要求,所有非抛出异常的return分支必须返回完全一致的类型。上述代码中lambda的两个返回分支分别返回bar和foo两种独立的自定义类型,编译器无法自动将二者统一推导为std::variant<bar,foo>目标类型,因此编译失败。
修复方案
两种改法均可正常编译运行,优先选择第一种,改动量最小:
- 方案1:显式指定lambda返回类型
为lambda添加尾置返回类型声明,明确返回值为目标entry类型,编译器会自动将bar、foo实例隐式转换为对应的variant对象,仅需修改lambda签名,核心修改后的transform逻辑如下:std::transform(bazzs.begin(),bazzs.end(),std::back_inserter(target), [](baz& bazzer) -> entry { switch(bazzer.foo_or_bar) { case 0: return converter{}(*(bazzer.asBar())); case 1: return converter{}(*(bazzer.asFoo())); default: throw std::runtime_error("ERROR"); } }); - 方案2:返回分支显式构造variant对象
不额外指定lambda返回类型,在每个返回分支中显式构造entry类型返回,保证所有return分支类型一致,满足自动推导规则,核心修改后的transform逻辑如下:std::transform(bazzs.begin(),bazzs.end(),std::back_inserter(target), [](baz& bazzer){ switch(bazzer.foo_or_bar) { case 0: return entry{converter{}(*(bazzer.asBar()))}; case 1: return entry{converter{}(*(bazzer.asFoo()))}; default: throw std::runtime_error("ERROR"); } });
内容的提问来源于stack exchange,提问作者user3001150
相关产品推荐
相关产品推荐

