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