这是因为我给了一个新用户一个答案,我建议他们使用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>;
std::variant<Item, Boxes> contents;
std::string label;
};
问题是,第一个变体,我可以写
if (box.contents.boxes.size() > 2) { foo(); }
如果我已经确定了会有子盒子,这就行了。
使用std::variant
,我必须编写:
if (std::get<Boxes>(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); }
};
然后是:
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 Empty&) { return 0; };
[](const Item&) { return 1; }
[](const Boxes& boxes) { return boxes.size(); } // non-recursive
}, *this);
}
};
然后你写:
if (box.size() > 2 ) { foo(); }
?