C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Return Value Optimisation whenever you need it (guaranteed elision)

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Sun, 16 Jul 2023 14:56:46 +0100
On Sun, Jul 16, 2023 at 2:13 PM Arthur O'Dwyer wrote:
>
> I think this is a legitimately interesting "puzzle"; although I don't think it currently merits any change to the core language nor to the standard library.


I'm not sure if we're singing from the same hymn sheet here. . .
but anyway I figured out how to return a mutex by value from a
function, and to have that mutex placed inside a global
'std::optional' variable.
Check it out:

      https://godbolt.org/z/5zqfb93bx

Next I will combine this code with my previous code so that we can:
      Step 1 : Return a locked mutex by value from a function
      Step 2 : Have that locked mutex placed inside a global
std::optional variable

And here's the GodBolt copy-pasted:

#include <optional> // optional

namespace detail {

    // An object of type 'Invoker' is returned
    // by value from PutRetvalInOptional::operator()

    template<typename T, typename... Params>
    class Invoker {
        std::optional<T> *const popt = nullptr;
        T (*const funcptr)(Params...);

    public:
        Invoker(std::optional<T> &argO, T (*const argF)(Params...)) :
popt(&argO), funcptr(argF) {}

        void operator()(Params... args) const
        {
            // 'std::optional<T>' inherits privately from
'std::_Optional_base<T>'
            auto &base =
*static_cast<std::_Optional_base<T>*>(static_cast<void*>(popt));

            // The next two lines take advantage of a feature of the
            // System V x86_64 calling convention. The return value
            // can be placed as the first parameter (because both
            // use the RDI register).
            void (*const magic)(T*, Params...) = reinterpret_cast<void
(*)(T*, Params...)>(funcptr);
            magic( &base._M_payload._M_payload._M_value,
std::forward<Params>(args)... );

            // Lastly we need to manually set the 'has_value()' of the
'std::optional' to 'true'
            base._M_payload._M_engaged = true;
        }

        Invoker(Invoker &&) = delete;
        Invoker(Invoker const & ) = delete;
        Invoker &operator=(Invoker &&) = delete;
        Invoker &operator=(Invoker const & ) = delete;
    };
} // close namespace 'detail'

template<typename T>
class PutRetvalInOptional {
    std::optional<T> *const popt;
public:
    PutRetvalInOptional(std::optional<T> &arg) : popt(&arg) {}

    template<typename... Params>
    detail::Invoker<T,Params...> operator()(T (*funcptr)(Params...))
    {
        return detail::Invoker<T,Params...>(*popt, funcptr);
    }

    PutRetvalInOptional(PutRetvalInOptional &&) = delete;
    PutRetvalInOptional(PutRetvalInOptional const & ) = delete;
    PutRetvalInOptional &operator=(PutRetvalInOptional &&) = delete;
    PutRetvalInOptional &operator=(PutRetvalInOptional const & ) = delete;
};

// ===================== Here comes the test code:
==========================================

#include <iostream> // cout
using std::cout, std::endl;

struct Mutex {
    // ---------- cannot move and cannot copy ----------
    Mutex(Mutex &&) = delete;
    Mutex(Mutex const & ) = delete;
    Mutex &operator=(Mutex &&) = delete;
    Mutex &operator=(Mutex const & ) = delete;

    Mutex(void) { cout << "construct\n"; }
    void lock(void) { cout << "lock\n" ; }
    void unlock(void) { cout << "unlock\n" ; }
    ~Mutex(void) { cout << "destroy\n" ; }
};

Mutex GiveMeMutex(int const a, double const b, char const *const p)
// dummy parameters
{
    cout << "Args: " << a << " " << b << " " << p << endl;

    return Mutex(); // cannot be copied, cannot be moved
}

std::optional<Mutex> om;

int main(int const argc, char **const argv)
{
    PutRetvalInOptional(om)(GiveMeMutex)(7,4.2,"Hello World");

    // GiveMeMutex has returned a mutex by value
    // ...and that mutex is now inside a global optional

    om->lock();
    om->unlock();
}

Received on 2023-07-16 13:56:56