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

如何区分pr-value与x-value并限制my_type构造函数参数类型

问题描述

给定以下C++代码:

#include <utility>

struct literal_type
{
    // ...
};

class my_type
{
public:
    my_type(literal_type const& literal);    // (1)
    my_type(literal_type     && literal);    // (2)

    // ...
};

void foo()
{
    literal_type literal_var { /* ... */ };

    my_type var1 (literal_var);       // 调用(1)
    my_type var2 (std::move(literal_var));    // 调用(2)
    my_type var3 (literal_type{});    // 调用(2)
}

已知var1构造时传入的是左值(l-value),var2的参数是亡值(x-value),var3的参数是纯右值(pr-value)。现在希望my_type的构造函数仅接受var3这类纯右值参数,让var1和var2触发编译错误。移除构造函数(1)可以解决var1的问题,但无法区分var2的亡值和var3的纯右值,请问是否有方法区分二者?

解决方案

要实现只让纯右值(pr-value)构造my_type,同时拒绝左值和亡值(x-value),可以用下面两种方法:

方法1:C++20用requires约束直接限制

直接给移动构造函数加个编译期约束,只有参数是纯右值的时候才允许调用:

#include <utility>
#include <type_traits>

struct literal_type
{
    // ...
};

class my_type
{
public:
    // 先把拷贝构造删了,彻底禁止左值传入
    my_type(const literal_type&) = delete;

    // 只接受纯右值的构造函数
    my_type(literal_type&& literal) requires std::is_prvalue_v<decltype(literal)>
    {
        // 构造逻辑
    }
};

void foo()
{
    literal_type literal_var {};

    my_type var1(literal_var);       // 编译报错:拷贝构造已删除
    my_type var2(std::move(literal_var));    // 编译报错:不满足requires条件
    my_type var3(literal_type{});    // 正常编译:参数是纯右值
}

方法2:用SFINAE兼容C++11及以上版本

如果要兼容旧标准,可以用模板构造函数配合类型萃取来筛选:

#include <utility>
#include <type_traits>

struct literal_type
{
    // ...
};

class my_type
{
public:
    // 删除拷贝构造,封死左值路径
    my_type(const literal_type&) = delete;

    // 把普通移动构造也删了,避免匹配x-value
    my_type(literal_type&&) = delete;

    // 模板构造函数,只匹配pr-value的情况
    template<typename T, typename = std::enable_if_t<
        std::is_same_v<std::decay_t<T>, literal_type> &&
        std::is_prvalue_v<decltype(std::declval<T>())>
    >>
    my_type(T&& literal)
    {
        // 这里处理构造逻辑就行
    }
};

void foo()
{
    literal_type literal_var {};

    my_type var1(literal_var);       // 编译报错:拷贝构造已删
    my_type var2(std::move(literal_var));    // 编译报错:匹配到被删除的移动构造
    my_type var3(literal_type{});    // 正常编译:匹配模板构造
}

原理说明

纯右值是临时对象或者字面量这种没有实体标识的表达式,而亡值是被std::move转换后、原本有实体的对象。std::is_prvalue_v能在编译期判断表达式的类别,刚好可以精准区分这两种右值,从而只放行纯右值的构造请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 00:05:25