Perfect forwarding with a temporary shell

Consider the following code in C++14, following the messages here , here and here :

// Include
#include <tuple>
#include <iostream>
#include <type_traits>

// Temporary function queue declaration
template <class... F>
class temporary_function_queue;

// Apply function queue declaration
template <class... F>
constexpr temporary_function_queue<F&&...> apply_function_queue(F&&... f);

// Temporary function queue definition
template <class... F>
class temporary_function_queue final
{
    // Types
    private:
    using const_lvalue_reference = const temporary_function_queue&;
    using rvalue_reference = temporary_function_queue&&;
    using temporary_type = temporary_function_queue<F&&...>;
    using data_type = std::tuple<F&&...>;

    // Lifecycle
    private:
    temporary_function_queue(rvalue_reference) = default;
    temporary_function_queue(const_lvalue_reference) = delete;
    temporary_function_queue operator=(rvalue_reference) = delete;
    temporary_function_queue operator=(const_lvalue_reference) = delete;
    explicit constexpr temporary_function_queue(F&&... f)
    : _f{std::forward<F>(f)...}
    {
    }

    // Temporary creator
    public:
    friend constexpr temporary_type apply_function_queue<>(F&&... f);

    // Apply function queue declaration
    public:
    template <class... Args> 
    decltype(auto) operator()(Args&&... args) const&&
    {
        // Do I need to do std::forward on f0 too? If so, how?
        return std::get<0>(_f)(std::forward<Args>(args)...);
    }

    // Data members
    private:
    data_type _f;
};

// Apply function queue definition
template <class... F>
constexpr temporary_function_queue<F&&...> apply_function_queue(F&&... f)
{
    return temporary_function_queue<F&&...>(std::forward<F>(f)...);
}

/* Example of use
int main(int argc, char* argv[])
{
    apply_function_queue(
        [](auto i){std::cout<<0<<std::endl;},
        [](auto i){std::cout<<1<<std::endl;}
    )(0);
    return 0;
}
*/

The goal is to create the following call syntax:

apply_function_queue(f0, f1, f2)(a, b, c, d, e);

Where f0, f1, f2are pointers to functions, functors, lambdas ... and where a, b, c, d, eare arguments that should be perfectly redirected. This function should create a temporary type, and then call operator()this temporary type, and this operator should perform an ideal transfer fn(for now f0, it will be changed later) with arguments a, b, c, d, e.... temporary_function_queuecannot be used in any other context.

, , lvalue... , ? undefined? , ( , , -O3 )

+4
1

: .

auto make_f(); // return by value
auto&& q = apply_function_queue(make_f());
// q holds dangling rvalue reference
q(a, b, c); // whoops...

. :

template<class... T> void f(T&&... p) {}

. , : T... T&&....

lvalue R rvalue Q:

R a;
f(a, Q{});

T... R&, Q, T&&... R&, Q&&.

p T&&....

'decltype'(std::forward<T>(p)...) === T&&...

(. decltype - .)

, (T...) /, / rvalue (T&&...) /.


&& , apply_function_queue . ( temporary_function_queue<F&&...> apply_function_queue, && temporary_function_queue. && , temporary_function_queue<F&&...>.)

, && , , &&.

. ( F..., F&&....) , && apply_function_queue.

:

apply_function_queue

:

template <class... F>
constexpr temporary_function_queue<F...> apply_function_queue(F&&... f);

:

template <class... F>
constexpr temporary_function_queue<F...> apply_function_queue(F&&... f)
{
    return temporary_function_queue<F...>(std::forward<F>(f)...);
}

temporary_type

temporary_function_queue<F...> not temporary_function_queue<F&&...>!

using temporary_type = temporary_function_queue<F...>;

friend constexpr temporary_type apply_function_queue<F...>(F&&... f);

rvalue , /, .

decltype(auto) operator()(Args&&... args) const&& ,

decltype(std::get<0>(_f)) === std::tuple_element_t<0u, data_type>&

lvalue. , , , tuple_element::type.

, :

return static_cast<std::tuple_element_t<0u, data_type>>(
    std::get<0>(_f))(std::forward<Args>(args)...);

( ):

return std::forward<std::tuple_element_t<0u, data_type>>(
    std::get<0>(_f))(std::forward<Args>(args)...);
+1

Source: https://habr.com/ru/post/1668775/


All Articles