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

如何在T禁用拷贝/移动构造且构造函数私有时返回std::expected<T,E>

解决私有构造函数下std::expected的构造问题

问题分析

当把Display接收wl_display*的构造函数设为私有后,create方法里的return {ptr}会报错,原因是std::expected不是Display的友元,无法访问私有构造函数来创建内部的Display实例。已知添加移动构造可以解决,但以下是不需要移动构造的替代方案:


方案1:将std::expected<Display, Error>声明为Display的友元

直接让std::expected拥有访问Display私有成员的权限,这样它就能直接调用私有构造函数来就地构造内部对象:

class Display
{
private:
    struct wl_display *ptr;
    Display(struct wl_display *ptr)
        : ptr{ptr}
    {
    }

    // 关键:声明友元,允许std::expected访问私有构造
    friend std::expected<Display, Error>;

public:
    enum class Error
    {
        CannotCreateDisplay,
    };

    Display() = delete;
    Display(const Display &) = delete;
    Display(Display &&) = delete;
    Display &operator=(const Display &) = delete;
    Display &operator=(Display &&) = delete;
    ~Display()
    {
        wl_display_destroy_clients(this->ptr);
        wl_display_destroy(this->ptr);
    }

    static std::expected<Display, Error> create()
    {
        struct wl_display *ptr{wl_display_create()};
        if (ptr == nullptr) {
            return std::unexpected{Error::CannotCreateDisplay};
        }
        // 两种写法都可行:
        return std::expected<Display, Error>(std::in_place, ptr);
        // 或者简化为 return {ptr};(视编译器对列表初始化的支持而定)
    }
};

优势:完全不需要移动或拷贝构造,Display对象直接在std::expected的内存空间中就地构造,没有额外开销。


方案2:使用C++23的std::make_expected(需编译器支持)

如果你的项目已经升级到C++23,可以用std::make_expected来简化构造逻辑,同样需要配合友元声明:

// 同样需要在Display类中添加友元声明:friend std::expected<Display, Error>;

static std::expected<Display, Error> create()
{
    struct wl_display *ptr{wl_display_create()};
    if (ptr == nullptr) {
        return std::unexpected{Error::CannotCreateDisplay};
    }
    return std::make_expected<Display, Error>(ptr);
}

原理:std::make_expected会自动就地构造Display对象,省去手动写std::in_place的麻烦,本质和方案1一致。


为什么原代码报错?

std::expected要构造内部的Display实例,必须调用Display的构造函数。当构造函数私有后,只有Display的成员函数和友元能调用它——std::expected不在此列,因此无法完成构造。而添加移动构造的解决方案,是让create先构造局部Display对象,再通过移动构造把对象转移到std::expected中,但这依赖移动语义,并非最优解。

内容的提问来源于stack exchange,提问作者Ogromny

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:53:18