考虑以下因素:
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&相同。我不想那样做。
老派会定义 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;
但是如果您想避免重复,您需要为此类返回类型创建一些样板库。