在运行时决定返回类型是右值还是左值时,如何避免不必要的复制?

Posted

技术标签:

【中文标题】在运行时决定返回类型是右值还是左值时,如何避免不必要的复制?【英文标题】:How to avoid unnecessary copying when whether the return type is a Rvalue or an Lvalue is decided at run time? 【发布时间】:2019-11-16 12:09:33 【问题描述】:

考虑下面一行

const auto x = condition ? getLvalue() : getRvalue();

因为x是const,我不需要复制getLvalue返回的值,如果我能引用它我会很高兴。当然,以下不会编译

const auto& x = condition ? getLvalue() : getRvalue(); // Compilation error

因为引用 R 值是没有意义的。

我该如何解决这个问题?有问题还是我可以相信编译器理解getLvalue 的返回类型不需要复制?

【问题讨论】:

你试过const auto&& x = ...吗? 我们称 && 为通用参考。也许有点过时但值得一读here 您可以使用std::move(getLvalue()) @AlexHodges 你确定这会有所帮助吗?无论如何,条件表达式的值类别是固定的,所以通用引用对 AFAIK 没有帮助 ... 通用引用将成为左值或右值,具体取决于它的初始化内容。由于您的参考可以是 l 或 r,因此使用通用参考似乎很合适,然后 std::forward 到任何需要参考的地方。 【参考方案1】:

有点接近,但也许是std::variant<T, std::reference_wrapper<T>>

您不能真正使用三元运算符进行赋值,因为它需要 std::common_type,但它适用于常规 if...else

Demo(需要 C++17)

代码:

int choice = 0;
std::cin >> choice;
std::variant<int, std::reference_wrapper<int>> opt;
if (choice == 0)
    opt = getRValue();
else
    opt = std::ref(getLValue());

getRValue()getLValue() 的存根:

int& getLValue()
    static int foo = 42;
    return foo;


int getRValue()
    return 1337;

我们可以访问变体进行打印:

struct visitor

    void operator()(int _val)
    
        std::cout << "rvalue value: " << _val;
    
    void operator()(std::reference_wrapper<int> _val)
    
        std::cout << "reference_wrapper value: " << _val << std::endl;
        _val += 1;
    
;

reference_wrapper 重载中,我增加了值,以便我们可以确定它仍然是一个引用。

【讨论】:

以上是关于在运行时决定返回类型是右值还是左值时,如何避免不必要的复制?的主要内容,如果未能解决你的问题,请参考以下文章

从函数返回的左值引用实际上是右值吗(从调用者的角度来看)?

完美转发

c++ 移动语义及使用

为啥字符串文字是左值,而所有其他文字都是右值?

golang os清空返回值

左值右值右值引用与move()forward()