You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

让std::expected调用类私有构造函数:设友元仍编译出错的问题

问题与解决方案

问题背景

我想要创建一个不可拷贝、不可移动的类,对象只能通过create静态函数构造(而非公有构造函数),create返回std::expected对象:要么持有构造完成的类实例,要么持有错误码。为了强制通过create构造,我把所有构造函数设为私有,核心目的是实现无异常的对象构造。

我尝试将std::expected<Foo, std::error_code>设为友元,允许它调用私有构造函数,但编译依然报错。示例代码如下:

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

错误原因

问题出在STL对std::expected的内部实现:直接友元std::expected<Foo, std::error_code>并不足够,因为实际负责构造Foo对象的是std::expected内部的辅助类(比如libstdc++中的__expected_storage,或其他STL实现里的类似内部结构),而非std::expected本身。这些内部类不在友元列表中,因此无法访问Foo的私有构造函数。

解决方案

最稳妥且跨平台的方案是使用标签分派(Tag Dispatch),既保留构造的私有性,又不需要依赖STL的内部实现:

修正后的代码

#include <expected>
#include <system_error>

class Foo
{
    int val_{};
    // 私有标签类型,仅Foo内部可访问
    struct ConstructorTag {};

public:
    Foo() = delete;
    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;
    // 禁止移动操作
    Foo(Foo&&) = delete;
    Foo& operator=(Foo&&) = delete;

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

        // 传递私有标签,调用构造函数
        return std::expected<Foo, std::error_code>{std::in_place, ConstructorTag{}, val};
    }

    // 公有构造函数,但必须传入私有标签才能调用
    explicit Foo(ConstructorTag, int val) noexcept
        : val_{val}
    {}
};

方案优势

  • 完全不依赖STL内部实现,跨平台兼容性好
  • 依然能强制外部只能通过create函数构造Foo对象
  • 实现了无异常的构造逻辑,符合最初的设计目标

内容的提问来源于stack exchange,提问作者k.st.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:16:29