Complex tuple capture

171 views Asked by At

I'm trying to figure out a way to capture a variadic pack that can consist out of l and r values references and capture the r-values by value while capturing the l-values by reference for later use (hence the async test). I tried the following:

#include <iostream>
#include <tuple>
#include <future>

template<typename... T>
auto bar(T&&... values)
{
    return [tup = std::forward_as_tuple(values...)](){
        std::cout << std::get<0>(tup) << std::endl;
    };
}

int lValue = 50;

int main ()
{
    auto rvalues = bar(50);
    auto lvalues = bar(lValue);

    auto futureR(std::async(rvalues));
    auto futureL(std::async(lvalues));
    futureR.get();
    futureL.get();
    return 0;
}

This however outputs an undefined value when executing the rvalues lambda. The lvalues lambda outputs the desired 50 without copy constructing (might be used with big objects). Is there some way to capture the r-value by value, without copy constructing objects that are passed by l-value reference not knowing what kind of combination of l and r values I will get?

auto mixedValues = bar(50, lValue);
auto futureMixed(std::async(mixedValues));

Link to example shell http://cpp.sh/336lv

1

There are 1 answers

1
Casey On BEST ANSWER

In:

template<typename... T>
auto bar(T&&... values)
{
    return [tup = std::forward_as_tuple(values...)](){
        std::cout << std::get<0>(tup) << std::endl;
    };
}

thanks to the magic of reference collapsing, T is an lvalue reference type for arguments that are lvalues, and a non-reference type for arguments that are rvalues. You therefor want:

return [tup = std::tuple<T...>(std::forward<T>(values)...)](){
    std::cout << std::get<0>(tup) << std::endl;
};

to store lvalues as references and rvalues by value.