如何为一个拥有 nocopy-nomove 类型的类编写一个 ctor,其中一个类型要从另一个类型(可以是多种类型中的一种)进行 init.ed?

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

我从这样的场景开始:

  • 不可复制、不可移动的类
    Foo1
    Foo2
    Baz
    是不可触及的
    struct Foo1 { Foo1(int); Foo1(Foo1&&) = delete; }; // I can't touch it
    struct Foo2 { Foo2(int); Foo2(Foo2&&) = delete; }; // I can't touch it
    struct Baz { Baz(Foo1&); Baz(Foo2&); Baz(Baz&&) = delete; }; // I can't touch it
    
  • 第四个班级,
    Bar
    ,我可以控制,最初看起来像这样:
    struct Bar {
        Bar(int i)
            : i{i}
            , foo{i}
            , baz{foo}
        {}
        int i;
        Foo1 foo;
        Baz baz;
    };
    

稍后,需要

Bar::foo
实际上是
Foo1
Foo2
,具体取决于馈送到
i
构造函数的
Bar

我最初的想法是使用

std::variant
,但是更改
Bar
来满足新要求并不完全简单,因为
Foo1
Foo2
Baz 的不可复制或可移动性
,妨碍:

  • Foo1 foo;
    更改为
    std::variant<Foo1, Foo2> foo;
    会导致初始化
    foo{i}
    无法编译,这是正常的,但我们也简化一下,现在我们仍然只在
    Foo1
    中放置
    foo
    ,将
    foo{i}
    更改为
    foo{Foo1{i}}
    ;这仍然不起作用,因为
    Foo1
    ;
  • 不可移动
  • 所以我想,好吧,我需要在
    Foo1
    中构建
    std::variant
    ;如果
    Bar
    没有
    Baz
    成员,这将是可行的,因为我可以通过在其中包含
    std::variant
    来使
    std::monostate
    默认可构造(这也将允许有条件构造
    Foo1
     Foo2
    struct Bar {
        Bar(int i)
            : i{i}
            //, baz{foo}
        {
            if (i == 0) {
                foo.emplace<Foo1>(i);
            } else {
                foo.emplace<Foo2>(i);
            }
        }
        int i;
        std::variant<std::monostate, Foo1, Foo2> foo{};
        //Baz baz;
    };
    

上述观察使我认为解决方案可以使用

std::unique_ptr
,但它也需要相当多的代码,因为必须
std::visit
才能构造
Baz

struct Bar {
    using Var = std::variant<std::unique_ptr<Foo1>, std::unique_ptr<Foo2>>;
    Bar(int i)
        : i{i}
        , foo{i == 0 ? Var{std::make_unique<Foo1>(i)} : Var{std::make_unique<Foo2>(i)}}
        , baz{std::visit([](auto&& p) { return Baz{*p}; }, foo)}
    {}
    int i;
    Var foo;
    Baz baz;
};

我想知道我是否错过了一些更干净的方法来处理这种情况。

c++ c++17 idioms noncopyable nonmovable
1个回答
0
投票

您可以构建变体,无需

std::monostate

struct Bar {
    using Foo = std::variant<Foo1, Foo2>;
    Bar(int i)
        : i{i}
        , foo{i == 0 ? Foo(std::in_place_type<Foo1>, i) : Foo(std::in_place_type<Foo2>, i)}
        , baz{std::visit([](auto&& p) { return Baz{p}; }, foo)}
    {}
    int i;
    std::variant<Foo1, Foo2> foo;
    Baz baz;
};

演示 不幸的是,msvc 拒绝该代码,但使用中间函数可以。

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