Boost logo

Boost :

Subject: Re: [boost] Formal Review Request: mp11
From: Peter Dimov (lists_at_[hidden])
Date: 2017-03-19 10:41:27


Vicente J. Botet Escriba wrote:

> About the infamous tuple_cat challenge. tuple_cat doesn't append. tuple
> cat construct a tuple with the elements of its tuple-like parameters...

That's quite true. The tuple_cat implementation in the article is a
straightforward reimplementation of Eric's tuple_cat, to illustrate the
difference in styles. It fixes one limitation of the original, but others
remain. Specifically, it doesn't work when the arguments are const
qualified, when the tuple elements are move-only (although this is a defect
in std::get), or for tuple-likes apart from std::pair.

Fixing those defects one by one:

1. tuple<unique_ptr<int>> can be fixed by replacing

template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
    return R{ std::get<Ks::value>(std::get<Is::value>(tp))... };
}

with

template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
    return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}

This shouldn't be necessary though; it's std::get that is broken here.

2. const-qualified tuples:

template<class... Tp,
    class R = mp_append<std::tuple<>, typename
std::remove_reference<Tp>::type...>>
    R tuple_cat( Tp &&... tp )

needs to be replaced with

template<class T> using remove_cv_ref =
std::remove_cv_t<std::remove_reference_t<T>>;

template<class... Tp,
    class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
    R tuple_cat( Tp &&... tp )

and the same substitution needs to be done for

    using list1 = mp_list<mp_rename<typename
std::remove_reference<Tp>::type, mp_list>...>;

3. tuple-like types:

template<class... Tp,
    class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
    R tuple_cat( Tp &&... tp )

needs to be further massaged as follows:

template<class N, class T> using element_ = std::tuple_element_t<N::value,
T>;
template<class T> using from_tuple_like = mp_product<element_,
mp_iota<std::tuple_size<T>>, mp_list<T>>;

template<class... Tp,
    class R = mp_append<std::tuple<>,
from_tuple_like<remove_cv_ref<Tp>>...>>
    R tuple_cat( Tp &&... tp )

and similarly for list1:

    using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;

With these changes, this now works:

{
    std::array<int, 2> const t1{ 1, 2 };
    std::array<float, 3> const t2{ 3.0f, 4.0f, 5.0f };
    std::array<std::unique_ptr<int>, 1> t3{ std::unique_ptr<int>{ new
int } };

    using expected = std::tuple<int, int, float, float, float,
std::unique_ptr<int>>;

    auto result = ::tuple_cat( t1, std::move( t2 ), std::move( t3 ) );

    static_assert( std::is_same<decltype(result), expected>::value, "" );

    PRINT_TYPE( decltype(result) );

    print_tuple( result );
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk