如何使 std::variants 的使用在语法上更加 "讨人喜欢"?

问题描述 投票:0回答:1

这是由我给一个新手用户的回答所引起的,我建议他们使用 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() 调用,并使他们的生活更加愉快?

c++ c++17 idiomatic syntactic-sugar std-variant
1个回答
4
投票

只需添加一些访问器来包装 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(); }

0
投票

"访问 "的方法怎么样? 类似这样的。

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

?

© www.soinside.com 2019 - 2024. All rights reserved.