Search code examples
c++c++23

Allow std::expected to use a private constructor


I try to create a non-copyable and non-movable class, whose object construction should only be done via a create function instead of public constructors. The create function will return a std::expected object either holding the created object or an error object. In order to enforce construction via the create function I want to make all available constructors private. Main purpose of this approach is object construction without exceptions.

Here is a simple example:

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 }
    {};

};

Please note, that I made std::expected<Foo, std::error_code> a friend in order to allow it to call the private constructor. But still I get a compiler error. Here is the code in Compiler Explorer.


Solution

  • You can use 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}; }
        );
    }
    

    Demo