C++ Logo

std-discussion

Advanced search

Re: std::get on const rvalue

From: Yongwei Wu <wuyongwei_at_[hidden]>
Date: Thu, 8 Dec 2022 09:58:27 +0800
On Thu, 8 Dec 2022 at 03:27, Julien Villemure-Fréchette <
julien.villemure_at_[hidden]> wrote:

> > The background is that some people in the team are arguing that we
> should forbid std::move on const objects.
>
> That's not exactly right, its not about calling std::move or not:, there's
> a very important distinction between calling std::move on an expression and
> move constructing/move assigning from an object.


I do not like the rule, but I need a case to argue against.


> A precise, more insightful way to express the guideline is:
>
> "If an object is going to be moved from, then it must not be declared
> const".
>
> Application of this rule is not concerned with the correct uses of
> std::move itself (there are other guidelines for this). Actually, more
> often than not, moving from an object should in fact be done without an
> explicit call to std::move:
>
> 1) for returning by value
> ```
> std:: string func()
> {
> std::string ret;
> // modify/build ret
>
> // good: return a locally declared complete object by value
> return ret;
>
> // bad: return with std::move
> // return std::move(ret);
> // see
> http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f48-dont-return-stdmovelocal
> }
> ```
> 2) for passing by value
> ```
> void g(std::unique_ptr<int>&& p);
>
> void h()
> {
> g(std::make_unique<int>(0));
> }
> ```
>
> In your example, the return type of the `get` function is critical to
> understand correctly the application of the rule "If an object is going to
> be moved from, then do not declare it const"; since
> `get(std::tuple<Types...> const&&)` returns a const rvalue reference, then
> it does not move construct/move assign anything, it merely forwards the
> indexed subobject with the same value category and qualifier as the tuple
> argument; so the rule is not applicable in this situation.
>
>
> Also, note that the example you pulled is an extremely peculiar one,
> production code almost never return by rvalue ref (even less const rvalue
> ref); see
> http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f45-dont-return-a-t
> .
> The special treatment of `get(std::tuple<Types...> const&&)` is only a
> special case of perfect forwarding for the const rvalue ref arguments
> (which is not likely to occur in runtime code, but may be important (and
> even necessary) for compile time type computations (ie, template
> metaprogramming)).


My question is exactly when ....

Specifically, if I want to implement a tuple-like object, is it necessary
to implement std::get on const rvalue reference?

template <size_t, typename T,
          std::enable_if_t<std::is_same_v<std::decay_t<T>, A>, bool> = true>
decltype(auto) get(T&&);

template <>
decltype(auto) get<0, A&>(A& a)
{
    return (a.m);
}

template <>
decltype(auto) get<0, const A&>(const A& a)
{
    return (a.m);
}

template <>
decltype(auto) get<0, A>(A&& a)
{
    return std::move(a.m);
}

template <>
decltype(auto) get<0, const A>(const A&& a)
{
    return std::move(a.m);
}

The rule I mentioned above would forbid the last specialization. The key
question remains: When would it be useful?

Best regards,

Yongwei

Received on 2022-12-08 01:58:39