最佳回报方式

问题描述 投票:0回答:1

考虑以下因素:

template <typename T>
struct S
{
    T Value() &&
    {
        // Option 1
        return value;
        // Option 2
        // return std::move(value);
        // Option 3
        // return T{std::move(value)};
    }

    T value;
};

我想确保当有人编写

auto var = S<ComplexType>{}.Value()
时(例如,显然在实际代码中它会更复杂),如果底层对象是可移动复制的,则通过移动构造返回值,否则通过复制构造返回值。

我根据自己的理解在代码中给出了3个选项,但正确的答案可能在其他地方。在这种情况下按值返回的最佳方式是什么?

进一步编辑:好的,我原来的例子不正确。这是我想要解决的根本问题。如果我说

template <typename T>
struct S
{
    T&& Value()&&
    {
        return std::move(value);
    }

    T value;
};

我基本上允许任何人通过说

auto var = S<ComplexType>{}; std::move(var).Value().CallNonConstMethod();
来获取我的对象的内部状态。与返回T&相同。我不想那样做。

c++ return-by-value
1个回答
0
投票

老派会定义 2 个重载:

T&  S::Value() const&
T&& S::Value() &&

具有几乎相同的代码。这对大多数人来说很烦人;考虑到 12 种不同的 cv+ref 限定符组合,这将是一件令人头疼的事情。

在 C++23 中我们可以做得更好一点:

T&  S::Value(this S const& self);
T&& S::Value(this S &&     self);

这个新语法使我们能够制作

this
模板参数类型:

template<typename self_t>
decltype(auto) S::Value(this self_t&& self){
    return std::forward_like<self_t>(self.value);
};

您也可以:

return std::forward<self_t>(self).value;

具有类似的效果。您还可以使用速记模板版本:

decltype(auto) S::Value(this auto&& self);

最后一个语法是调用该功能推论的灵感来源。出于模板元编程的原因,库开发人员更愿意避免推导的返回类型;如果您需要明确返回类型,那么尾随返回类型可以更简单地编写:

template<typename self_t> 
auto S::Value(this self_t&& self)
     ->decltype(std::forward<self_t>(self).value;

但是如果您想避免重复,您需要为此类返回类型创建一些样板库。

© www.soinside.com 2019 - 2024. All rights reserved.