The copy constructor of std::tuple
, even the converting one, obviously copies all the elements, and since a copy shouldn't change the copied-from element, they're marked as const
. This behaviour is perfectly reasonable, most of the time.
The workaround for your special case is a bit more involved that what you may like, but it works. The basic idea is that you, conceptually, don't want to copy the tuple, but you want to use it's elements as an initializer to the elements of your other tuple, as such their const
ness should be preserved.
template<unsigned...> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
namespace aux{
template<class... Ts, unsigned... Is>
std::tuple<Ts&...> tie_all_(std::tuple<Ts...>& other, seq<Is...>){
return std::tie(std::get<Is>(other)...);
}
} // aux::
template<class... Ts>
std::tuple<Ts&...> tie_all(std::tuple<Ts...>& other){
return aux::tie_all_(other, gen_seq<sizeof...(Ts)>());
}
The code is used like this: WrapperTuple w(tie_all(t));
. Now you can get rid of the Member const&
constructor.
You could even go further and write a function that turns a tuple into a wrapper tuple, thus getting rid of having to specify the type manually:
template<class... Ts>
std::tuple<A<Ts>...> wrap_all(std::tuple<Ts...>& other){
return tie_all(other);
}
// ...
auto w(wrap_all(t));
And if you have different wrapper classes:
template<template<class> class Wrapper, class... Ts>
std::tuple<Wrapper<Ts>...> wrap_all_in(std::tuple<Ts...>& other){
return tie_all(other);
}
// ...
auto w = wrap_all_in<A>(t);