Search code examples
c++tuplesc++14move

How to put objects in `std::tuple` and take the first item with move-only operations?


I use a lambda to put objects of different types in a tuple and pass it to a second lamda to get the first item. The idea is to only use move-only operations, but the following code still needs a copy to get the first items from the tuple.

#include <iostream>
#include <tuple>

struct foo {
    foo()=default;
    foo(const foo &) { std::cout << "COPY\n"; }
    foo(foo &&) { std::cout << "MOVE\n"; }

};

int main()
{
    auto lst = [](auto ...args) {
        return [tp = std::make_tuple(std::move(args)...)](auto lmb) { return lmb(tp); };
    };

    auto head = [](auto lmb) {
        return lmb([](auto tp) { return std::move(std::get<0>(tp)); });
    };

    foo f ;

    auto lmb = lst(std::move(f),1,2);

    std::cout << std::endl;

    auto r = head(std::move(lmb));
}

This produces the following output:

MOVE
MOVE

MOVE
COPY
MOVE

I don't understand where in the chain this copy takes place.

So the question is:
Is it possible to do this with move-only operations (and how) ?


Solution

  • The tuple, tp, is copied from here:

    return lmb(tp);
               ^^
    

    to here

    [](auto tp) { ... }
            ^^
    

    The first one needs to be return lmb(std::move(tp));

    You'll also need to make the lambda mutable since captures are const by default.

    [tp = std::make_tuple(std::move(args)...)](auto lmb) mutable { ... };
                                                         ^^^^^^^