I've written a class shrink_pair
which does the same like pair
but first
and second
are [[no_unique_address]]
.
I want to write a similar constructor like std::pair
's piecewise_construct
constructor. This constructor should call first
and second
's constructors by unpacking the first and second tuple and doing forward()-ing of the tuples elements.
std::apply
doesn't seem to work for me since I'm not calling a normal callable object but a constructor. How can I do that?
CodePudding user response:
I believe this is what std::make_from_tuple
(C 17) is for:
#include <tuple>
struct Foo {
Foo(int x, float y) {}
};
struct Bar {
Bar(int x, float y) {}
};
template <typename T, typename U>
struct Pair {
template <typename TupleT, typename TupleU>
Pair(TupleT&& first, TupleU&& second)
: first(std::make_from_tuple<T>(std::forward<TupleT>(first))),
second(std::make_from_tuple<U>(std::forward<TupleU>(second))) {}
T first;
U second;
};
int main() { Pair<Foo, Bar> p{std::tuple{1, 1.2f}, std::tuple{2, 2.0f}}; }
CodePudding user response:
For C 17 onwards, see @Quimby's answer.
For C 11 and C 14, you need to do it the old way with std::index_sequence
:
template <class U, class V>
class custom_pair {
template <std::size_t... UIs, std::size_t... VIs, class... UArgs, class... VArgs>
custom_pair(
std::index_sequence<UIs... >, std::tuple<UArgs... > u_args,
std::index_sequence<VIs... >, std::tuple<VArgs... > v_args) :
first(std::forward<UArgs>(std::get<UIs>(u_args))... ),
second(std::forward<VArgs>(std::get<VIs>(v_args))... ) { }
public:
U first;
V second;
public:
template <class... UArgs, class... VArgs>
custom_pair(std::piecewise_construct_t,
std::tuple<UArgs... > u_args,
std::tuple<VArgs... > v_args) :
custom_pair(
std::make_index_sequence<sizeof... (UArgs)>{}, std::move(u_args),
std::make_index_sequence<sizeof... (VArgs)>{}, std::move(v_args)) { }
};
The standard requires the std::pair
equivalent constructor to work for non-moveable type, so you cannot use intermediate function (such as a custom std::make_tuple
) in C 14, you have to unpack in the initializer-list of your custom pair constructor.
In C 17, you can use intermediate function such as std::make_tuple
since you get guaranteed copy-elision, as in @Quimby's answer.
Full example on godbolt: https://godbolt.org/z/7PsEjs18r