Tootsie
Tootsie

Reputation: 867

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) ?

Upvotes: 2

Views: 87

Answers (1)

kmdreko
kmdreko

Reputation: 60122

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 { ... };
                                                     ^^^^^^^

Upvotes: 4

Related Questions