我尝试创建一个不可复制且不可移动的类,其对象构造只能通过创建函数而不是公共构造函数来完成。 create 函数将返回一个std::expected包含已创建对象或错误对象的对象。为了通过创建函数强制构造,我想将所有可用的构造函数设为私有。这种方法的主要目的是无例外地构造对象。

这是一个简单的例子:

class Foo
{
    int val_{};

public:
    Foo() = delete;
    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;

    static auto
    create(int val) noexcept -> std::expected<Foo, std::error_code>
    {
        if (val == 42)
            return std::unexpected<std::error_code>(std::in_place, EINVAL, std::generic_category() );

        return std::expected<Foo, std::error_code>{ std::in_place, val };
    }

private:

    friend class std::expected<Foo, std::error_code>;

    explicit Foo(int val) noexcept
    : val_{ val }
    {};

};

请注意,我做了std::expected<Foo, std::error_code>一个friend以便允许它调用私有构造函数。但我仍然收到编译器错误。这是中的代码

3

  • 1
    有什么问题吗return Foo{val};


    – 

  • 1
    @Barry,return Foo{val};不起作用:


    – 

  • 是的,因为你让这种类型既不能移动也不能复制,这并没有使它看起来超级有用……


    – 


1 个回答
1

您可以使用expected::transform

static auto
create(int val) noexcept -> std::expected<Foo, std::error_code>
{
    if (val == 42)
        return std::unexpected<std::error_code>(std::in_place, EINVAL, std::generic_category() );
    
    return std::expected<int, std::error_code>{val}.transform(
      [](int i) { return Foo{i}; }
    );
}

3

  • 2
    好的! …而且它甚至不需要friend船!


    – 


  • 该解决方案令人印象深刻并解决了问题。然而,考虑到这可能是无异常编程的常见用例,它是一个相当麻烦的解决方案。令人遗憾的是,语言无法以更好的方式支持这一点。


    – 

  • 1
    @k.st。支持不可移动类型并不是“无异常编程的常见用例”。


    –