C++ 如何更多地使用std::variants“;可口的;,语法方面?
这是因为我给了一个新手一个答案,我建议他们使用一个而不是一个联盟 有了工会,你可能会有如下情况:C++ 如何更多地使用std::variants“;可口的;,语法方面?,c++,c++17,idioms,syntactic-sugar,std-variant,C++,C++17,Idioms,Syntactic Sugar,Std Variant,这是因为我给了一个新手一个答案,我建议他们使用一个而不是一个联盟 有了工会,你可能会有如下情况: struct Box { struct Item { float value; }; using Boxes = std::vector<Box>; union Value { Item item; Boxes boxes; }; Value contents; std::string label; };
struct Box {
struct Item { float value; };
using Boxes = std::vector<Box>;
union Value {
Item item;
Boxes boxes;
};
Value contents;
std::string label;
};
如果我已经建立了一些子框,这就行了
使用std::variant
,我必须写:
if (std::get<Boxes>(box.contents).size() > 2) { foo(); }
if(std::get(box.contents).size()>2){foo();}
我觉得第二个版本的可读性要差得多,有点混乱,而且相当分散注意力。另外-我必须知道框的类型
在我的代码中,我能做些什么,让我的用户不必进行这种std::get()
调用,让他们的生活更愉快?只需添加一些访问器,包装std::get
s:
struct Box {
struct Item { float value; };
using Boxes = std::vector<Box>;
std::variant<Item, Boxes> contents;
std::string label;
decltype(auto) item() { return std::get<Item>(contents); }
decltype(auto) item() const { return std::get<Item>(contents); }
decltype(auto) boxes() { return std::get<Boxes>(contents); }
decltype(auto) boxes() const { return std::get<Boxes>(contents); }
};
“参观”方式如何?大概是这样的:
struct Box {
struct Item { float value; };
using Boxes = std::vector<Box>;
std::variant<Item, Boxes> contents;
std::string label;
};
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
struct Box {
struct Item { float value; };
using Boxes = std::vector<Box>;
std::variant<Item, Boxes> contents;
std::string label;
decltype(auto) size() const {
return std::visit(overloaded {
[](const Item&) { return 1; }
[](const Boxes& boxes) { return boxes.size(); } // non-recursive
}, *this);
}
};
当访问std::variant
s@Mestkon:一般来说,这是有效的建议。但是假设我知道哪个是活动类型。使用std::variant
的if
与union
one做的不一样:它做了一个不必要的额外检查,因为您已经建立了子框。由于没有很好的方法可以避免这种检查,std::variant
不够通用,无法取代union
。因此,我避免推荐它。编译时间、codegen和详细语法也没有帮助。@Acorn:1。关于额外的支票你是对的。2.理论上,编译器可以意识到,至少在简单的情况下,检查是不必要的,并将其删除,但我不确定在实践中是否会发生这种情况。最好让非常量getter返回左值引用,而不是副本。。。但是+1。啊,对,对不起decltype(auto)
,需要记住它是这样做的。常量空(
)到底是什么?@PatrickParker:我在激励帖子中建议的内容的复制粘贴,不应该包含在这个答案中…:-(我把它拿走了。
if (box.boxes().size() > 2) { foo(); }
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
struct Box {
struct Item { float value; };
using Boxes = std::vector<Box>;
std::variant<Item, Boxes> contents;
std::string label;
decltype(auto) size() const {
return std::visit(overloaded {
[](const Item&) { return 1; }
[](const Boxes& boxes) { return boxes.size(); } // non-recursive
}, *this);
}
};
if (box.size() > 2 ) { foo(); }