It looks to me that the function did what you asked it to do. Doing it otherwise would be the unexpected behavior. What am I missing?

From: Std-Proposals <std-proposals-bounces@lists.isocpp.org> on behalf of Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org>
Sent: Sunday, March 10, 2024 2:48:34 PM
To: std-proposals@lists.isocpp.org <std-proposals@lists.isocpp.org>
Cc: Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>
Subject: Re: [std-proposals] Defect report for std::apply (or apply_perfectly)
 
On Sun, Mar 10, 2024 at 12:02 PM Jonathan Wakely wrote:
>
> Forward your tuple<T&&> as an rvalue not an lvalue.
>
> Why should std::apply work differently from everything else that uses std::get?


I'm not saying that std::get' should work differently here, but rather
that the result of it should be static_cast'ed before passing
arguments to the callable.

I can see one problem with passing the tuple object by Rvalue
reference, as demonstrated in the following code:

    #include <iostream>     // cout, endl
    #include <string>       // string
    #include <tuple>        // get, tuple, apply
    #include <utility>      // move

    using std::string;

    void Func(string &&a, string &b, string &&c)
    {
        static string s( std::move(a) );
    }

    int main(void)
    {
        string s("For oft when on my couch I lie, in vacant or in
pensive mood");

        std::tuple<string, string&, string&&> t = {
            "They flash upon that inward eye, which is the bliss of solitude",
            s,
            std::move(s)
        };

    //  std::apply( Func, t );     - fails to compile

        std::apply( Func, std::move(t) );

        std::cout << "Daffodils: " << std::get<0>(t) << std::endl;
    }

The reason I pass the tuple by Rvalue reference to 'std::apply' is so
that the third parameter to Func, i.e. "string &&c", will bind
successfully. I also want the second parameter to bind successfully --
which is an Lvalue reference. I don't however want the first parameter
to bind successfully -- I don't want to lose the content of the first
string in my tuple -- I want a compiler error here, and so I really
shouldn't have passed my tuple by Rvalue reference to begin with.

And so therefore I think either:
(a) A defect report should be raised for 'apply' so that the return
value from 'get' should be static_cast'ed.
(b) A new function should be added to the standard library called
'apply_perfectly'

Here's how 'apply_perfectly' can be coded:

     https://godbolt.org/z/fqc7Wja9s

    I've left out the 'noexcept(noexcept(............))' so you can
read it a little more easily.

And here it is copy-pasted:

#include <functional>   // invoke
#include <iostream>     // cout, endl
#include <string>       // string
#include <tuple>        // get, tuple, tuple_element, apply
#include <type_traits>  // conditional_t, is_lvalue_reference,
is_rvalue_reference, is_same, remove_reference
#include <utility>      // forward, index_sequence, make_index_sequence, move

namespace std {
    template<typename F, typename Tuple, size_t... I>
    constexpr decltype(auto) apply_perfectly_impl(F &&f, Tuple &&t,
index_sequence<I...>)
    {
#define tElem             tuple_element_t< I, remove_reference_t<Tuple> >
#define tElem_NoRef       remove_reference_t< tElem >
#define vElem_IsRef       (!is_same_v< tElem , tElem_NoRef >)
#define vElem_ShouldBeR   (is_rvalue_reference_v< tElem > ||
(!vElem_IsRef && !is_lvalue_reference_v<Tuple>))
#define tElem_CastTo      conditional_t< vElem_ShouldBeR ,
tElem_NoRef&&, tElem_NoRef& >

        return invoke( forward<F>(f), static_cast< tElem_CastTo >(
get<I>(t) )... );
    }

    template <typename F, typename Tuple>
    constexpr decltype(auto) apply_perfectly(F &&f, Tuple &&t)
    {
        return apply_perfectly_impl(
            forward<    F>(f),
            forward<Tuple>(t),
            make_index_sequence< tuple_size_v< remove_cvref_t<Tuple> > >{});
    }
}

using std::string;

void Func1(string &a, string &b, string &&c)
{
    static string s( a );
}

void Func2(string &&a, string &b, string &&c)
{
    static string s( std::move(a) );
}

int main(void)
{
    string s("For oft when on my couch I lie, in vacant or in pensive mood");

    std::tuple<string, string&, string&&> t = {
        "They flash upon that inward eye, which is the bliss of solitude",
        s,
        std::move(s)
    };

    std::apply_perfectly( Func1, t );
    std::cout << "Daffodils: " << std::get<0>(t) << std::endl;

//  std::apply_perfectly( Func1, std::move(t) );    // - fails to compile

//  std::apply_perfectly( Func2,           t  );   // - fails to compile

    std::apply_perfectly( Func2, std::move(t) );
    std::cout << "Daffodils: " << std::get<0>(t) << std::endl;
}
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals