2

这是由我给新手用户的答案所激发的,我建议他们使用 anstd::variant而不是 union。

使用工会,您可能会遇到以下情况:

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()调用,并使他们的生活更愉快?

4

2 回答 2

4

Just add some accessors wrapping 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); }
};

And then it goes:

if (box.boxes().size() > 2) { foo(); }
于 2020-06-12T11:41:56.183 回答
1

“访问”方法怎么样?像这样的东西:

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(); }

?

于 2020-06-12T12:59:45.550 回答