Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy two tuples with different sizes

I am experimenting with some tuples, and I find myself in the weird position of asking this: how can I copy two tuples that differ in their sizes? Of course, this is intended limited to the minimum length of the two tuples.

So, for instance, let's create three tuples:

std::tuple<int, char, float> a(-1, 'A', 3.14);

std::tuple<int, char, double> b = a;

std::tuple<long, int, double, char> c;

Now, a and b differ in types, and the assignment work (obviously). As for a and c the things get a little more confusing.

My first implementation failed, since I don't know how to recurse on variadic templates with a specific type, so something like this won't work:

template <class T, class U>
void cp(std::tuple<T> from, std::tuple<U> to)
{

}

template <class T, class... ArgsFrom, class U, class... ArgsTo>
void cp(std::tuple<T, ArgsFrom...> from, std::tuple<U, ArgsTo...> to)
{
    std::get<0>(to) = std::get<0>(from);
    // And how to generate the rest of the tuples? 
}

That function won't do anything. So I've devised a second failing attempt, using not the types, but the sizes:

template<class From, class To, std::size_t i>
void copy_tuple_implementation(From &from, To &to)
{
    std::get<i>(to) = std::get<i>(from);

    copy_tuple_implementation<From, To, i - 1>(from, to);
}

template<>
void copy_tuple_implementation<class From, class To, 0>(From &from, To &to)
{
}

template<class From, class To>
void copy_tuple(From &from, To &to)
{
    constexpr std::size_t from_len = std::tuple_size<From>::value;
    constexpr std::size_t to_len   = std::tuple_size<To>::value;

    copy_tuple_implementation<From, To, from_len < to_len ? from_len - 1 : to_len - 1>(from, to);
}

But that won't compile. I have too many errors to display here, but the most significant ones are:

Static_assert failed "tuple_element index out of range"
No type named 'type' in 'std::__1::tuple_element<18446744073709551612, std::__1::__tuple_types<> >'
Read-only variable is not assignable
No viable conversion from 'const base' (aka 'const __tuple_impl<typename __make_tuple_indices<sizeof...(_Tp)>::type, int, int, double>') to 'const __tuple_leaf<18446744073709551615UL, type>'

The interesting part is the index out of range, and the fact that I cannot copy an element with std::get<>.

Can anyone help me in this?

Thanks!

like image 492
senseiwa Avatar asked Feb 11 '26 03:02

senseiwa


2 Answers

Here's one possibility, using C++14's ready-made integer sequence template (but this is easily reproduced manually if your library doesn't include it):

#include <tuple>
#include <utility>

template <std::size_t ...I, typename T1, typename T2>
void copy_tuple_impl(T1 const & from, T2 & to, std::index_sequence<I...>)
{
    int dummy[] = { (std::get<I>(to) = std::get<I>(from), 0)... };
    static_cast<void>(dummy);
}

template <typename T1, typename T2>
void copy_tuple(T1 const & from, T2 & to)
{
    copy_tuple_impl(
        from, to,
        std::make_index_sequence<std::tuple_size<T1>::value>());
}

Example:

#include <iostream>

int main()
{
    std::tuple<int, char> from { 1, 'x' };
    std::tuple<int, char, bool> to;
    copy_tuple(from, to);
    std::cout << "to<0> = " << std::get<0>(to) << "\n";
}
like image 92
Kerrek SB Avatar answered Feb 15 '26 13:02

Kerrek SB


Another option is to use operator overloading to simulate partial-specialization of your function:

template <std::size_t N>
struct size_t_t {};

template<class From, class To, std::size_t i>
void copy_tuple_implementation(From &from, To &to, size_t_t<i>)
{
    std::get<i>(to) = std::get<i>(from);

    copy_tuple_implementation(from, to, size_t_t<i-1>{});
}

template<class From, class To>
void copy_tuple_implementation(From &from, To &to, size_t_t<0>)
{
    std::get<0>(to) = std::get<0>(from);
}

Or you could just use a helper class:

template<class From, class To, std::size_t i>
struct CopyTuple
{
    static void run(From &from, To &to)
    {
        std::get<i>(to) = std::get<i>(from);

        CopyTuple<From,To,i-1>::run(from, to);
    }
};

template<class From, class To>
struct CopyTuple<From,To,0>
{
    static void run(From &from, To &to)
    {
        std::get<0>(to) = std::get<0>(from);
    }
};
like image 28
TartanLlama Avatar answered Feb 15 '26 12:02

TartanLlama



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!