你如何使std::变体的使用更"palatable",语法方面?

How do you make the use of std::variants more "palatable", syntax-wise?

本文关键字:palatable 语法 方面 何使 std      更新时间:2023-10-16

这是由我给新手用户的一个答案引起的,我建议他们使用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(); }

我觉得第二个版本的可读性要差得多,有点混乱,而且很分散注意力。另外 - 我必须知道boxes的类型.

在我的代码中,我可以做些什么来使我的用户无需进行这种std::get()调用,并使他们的生活更加愉快?

只需添加一些包装std::gets的访问器:

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 Item&)        { return 1; }
[](const Boxes& boxes) { return boxes.size(); } // non-recursive
}, *this);
}
};

然后你写:

if (box.size() > 2 ) { foo(); }