Gabriel
Gabriel

Reputation: 9432

How to construct a tuple of non-movable non-copyable objects?

Is it possible to construct such a tuple somehow?

#include <tuple>

struct A
{
    A() = default;
    A(const A&) = delete;
    A(A&&) = delete;
};

auto generate()
{
    // Funktion which constructs a tuple on one line...
    return std::make_tuple(A{},A{});
}

int main()
{
    auto t = generate();
}

Is this possible in C++14 and is this possible in C++17 which forces Return-Value-Optimization (unnamed prvalue return expression)??

Live

Upvotes: 3

Views: 567

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275500

std::tuple<A,A> generate() { return {}; }

If you need to non-default construct A:

template<class U, class F>
struct maker_t{ operator U(){ return f(); } F f; };
template<class U, class F>
maker_t<U,std::decay_t<F>> maker(F&& f){ return {std::forward<F>(f)}; }

Now you can:

std::tuple<A,A> generate() {
  return {
    maker<A>( []{ return A{}; } ),
    maker<A>( []{ return A{}; } )
  };
}

where those lambdas can do anything that returns an A.

Upvotes: 2

Nicol Bolas
Nicol Bolas

Reputation: 473537

tuple's constructor that initializes the objects from arguments of the exact same types as the tuple's template parameters requires that the types are copy-constructible. However, if all of the types are default-constructible, then you can do that. So you could just have generate issue a return tuple<A, A>{};. This works in C++17.

If you want to initialize them with a value, then you can use the tuple constructor that uses explicit conversion from a sequence of types that aren't the same as the tuple parameters. There, you can use C++17 guaranteed copy elision, but only if the source types use an operator Type() overload and follow the rules of guaranteed elision.

Upvotes: 3

Related Questions