1
template<std::size_t ENUM>
struct createP2E
{    static constexpr std::size_t SIZE = 1;
     static constexpr std::size_t P2E[SIZE] = {ENUM};
};

template<typename A, typename B>
struct combine;

template<>
struct combine<createP2E<2>, createP2E<3> >
{       static constexpr std::size_t SIZE = 2;
        static constexpr std::size_t P2E[2] = {2, 3};
        typedef combine type;
};
template<typename A>
struct combine<A, A>
{       typedef A type;
};

Is it possible to let the compiler create combine? And yes, I want arrays being created. More info: The argument to createP2E (position to enum) is an enumeration. The created array P2E should contain the enumerations in sorted order.

Edit after the fact:

I was potentially unclear in my question:

I want a merge of two provided sets via meta programming using constexpr instead of boost::mpl::set or boost::mp11::list<>. The resulting set should again be possible to be used for the merge.

  • 1
    What do you mean "let the compiler create combine"? As shown, the `combine` template has only two possible instances. One where both of its parameters are identical, or the one with `createP2E<2>` and `createP2E<3>` as the respective template parameters. That's the only `combine`s that can be created. – Sam Varshavchik May 14 '20 at 01:05
  • 1
    did you... try compiling it? – HotelCalifornia May 14 '20 at 01:58

1 Answers1

1

I guess it can be done. As you already have stated, the core problem here is append one array to another and then sort it. Here is a solution to this problem based on c++17. Unfortunately, it uses std::arrays and not c-array as you do.

I simply combined this answer and this code to get (full credit to them):

#include <iostream>
#include <array>

namespace detail
{
template<std::size_t ... Size>
struct num_tuple
{

};

template<std::size_t Prepend, typename T>
struct appender {};

template<std::size_t Prepend, std::size_t ... Sizes>
struct appender<Prepend, num_tuple<Sizes...>>
{
    using type = num_tuple<Prepend, Sizes...>;
};

template<std::size_t Size, std::size_t Counter = 0>
struct counter_tuple
{
    using type = typename appender<Counter, typename counter_tuple<Size, Counter+1>::type>::type;
};


template<std::size_t Size>
struct counter_tuple<Size, Size>
{
    using type = num_tuple<>;
};

}


template<typename T, std::size_t LL, std::size_t RL, std::size_t ... LLs, std::size_t ... RLs>
constexpr std::array<T, LL+RL> join(const std::array<T, LL> rhs, const std::array<T, RL> lhs, detail::num_tuple<LLs...>, detail::num_tuple<RLs...>)
{
    return {rhs[LLs]..., lhs[RLs]... };
};


template<typename T, std::size_t LL, std::size_t RL>
constexpr std::array<T, LL+RL> join(std::array<T, LL> rhs, std::array<T, RL> lhs)
{
    //using l_t = typename detail::counter_tuple<LL>::type;
    return join(rhs, lhs, typename detail::counter_tuple<LL>::type(), typename detail::counter_tuple<RL>::type());
}


template<typename Array>
constexpr void comb_sort_impl ( Array & array_ ) noexcept {
    using size_type = typename Array::size_type;
    size_type gap = array_.size ( );
    bool swapped = false;
    while ( ( gap > size_type { 1 } ) or swapped ) {
        if ( gap > size_type { 1 } ) {
            gap = static_cast<size_type> ( gap / 1.247330950103979 );
        }
        swapped = false;
        for ( size_type i = size_type { 0 }; gap + i < static_cast<size_type> ( array_.size ( ) ); ++i ) {
            if ( array_ [ i ] > array_ [ i + gap ] ) {
                auto swap = array_ [ i ];
                array_ [ i ] = array_ [ i + gap ];
                array_ [ i + gap ] = swap;
                swapped = true;
            }
        }
    }
}

template<typename Array>
constexpr Array sort ( Array array_ ) noexcept {
    auto sorted = array_;
    comb_sort_impl ( sorted );
    return sorted;
}


struct
arr1
{
    static constexpr auto values = std::array<int, 9> { 6, 8, 0, 1, 1, 22, 9, 2, 7 };
};

struct
arr2
{
    static constexpr auto values = std::array<int,3>{0,12,5};
};

struct
sorted 
{
    static constexpr auto values 
        = sort ( join(arr1::values,arr2::values) );
};

int main ( ) {

    for ( auto i : sorted::values )
        std::cout << i << ' ';
    std::cout << std::endl;

    return EXIT_SUCCESS;
}

Here's a live demo.

Remark: If combine will always only combine two createP2E which store one element, there might be much simpler solutions. However, this general approach allows you, to combine a two combine objects. However, you need to add some functionality which removes duplicates from the combined array to have a proper enumeration.

UPDATE Here is a solution with returns an sorted array with the duplicates removed. It is not nice, but it does the job (live demo):

#include <iostream>
#include <array>

namespace detail
{
template<std::size_t ... Size>
struct num_tuple
{

};

template<std::size_t Prepend, typename T>
struct appender {};

template<std::size_t Prepend, std::size_t ... Sizes>
struct appender<Prepend, num_tuple<Sizes...>>
{
    using type = num_tuple<Prepend, Sizes...>;
};

template<std::size_t Size, std::size_t Counter = 0>
struct counter_tuple
{
    using type = typename appender<Counter, typename counter_tuple<Size, Counter+1>::type>::type;
};


template<std::size_t Size>
struct counter_tuple<Size, Size>
{
    using type = num_tuple<>;
};

}


template<typename T, std::size_t LL, std::size_t RL, std::size_t ... LLs, std::size_t ... RLs>
constexpr std::array<T, LL+RL> join(const std::array<T, LL> rhs, const std::array<T, RL> lhs, detail::num_tuple<LLs...>, detail::num_tuple<RLs...>)
{
    return {rhs[LLs]..., lhs[RLs]... };
};


template<typename T, std::size_t LL, std::size_t RL>
constexpr std::array<T, LL+RL> join(std::array<T, LL> rhs, std::array<T, RL> lhs)
{
    //using l_t = typename detail::counter_tuple<LL>::type;
    return join(rhs, lhs, typename detail::counter_tuple<LL>::type(), typename detail::counter_tuple<RL>::type());
}


template<typename Array>
constexpr void comb_sort_impl ( Array & array_ ) noexcept {
    using size_type = typename Array::size_type;
    size_type gap = array_.size ( );
    bool swapped = false;
    while ( ( gap > size_type { 1 } ) or swapped ) {
        if ( gap > size_type { 1 } ) {
            gap = static_cast<size_type> ( gap / 1.247330950103979 );
        }
        swapped = false;
        for ( size_type i = size_type { 0 }; gap + i < static_cast<size_type> ( array_.size ( ) ); ++i ) {
            if ( array_ [ i ] > array_ [ i + gap ] ) {
                auto swap = array_ [ i ];
                array_ [ i ] = array_ [ i + gap ];
                array_ [ i + gap ] = swap;
                swapped = true;
            }
        }
    }
}






template<typename Array>
constexpr Array sort ( Array array_ ) noexcept {
    auto sorted = array_;
    comb_sort_impl ( sorted );
    return sorted;
}


struct
arr1
{
    static constexpr auto values = std::array<int, 9> { 6, 8, 0, 1, 1, 22, 9, 2, 7 };
};

struct
arr2
{
    static constexpr auto values = std::array<int,3>{0,12,5};
};

struct
sorted 
{
    static constexpr auto values 
        = sort ( join(arr1::values,arr2::values) );
};

template <typename T, std::size_t N>
constexpr auto size_without_duplicates (const std::array<T,N> &array_)
{
    std::array<T,N> ret = {};
    std::size_t count = 1; 
    ret[0] = array_[0];
    for (unsigned int i = 1; i < N; ++i)
        if (array_[i-1] != array_[i])
            ++count;

    return count;
}


template <class T>
constexpr auto remove_duplicates ()
{
    std::array<int,size_without_duplicates(T::values)> ret = {};
    unsigned int count = 0; 
    ret[0] = T::values[0];
    for (unsigned int i = 1; i < T::values.size(); ++i)
        if (T::values[i-1] != T::values[i])
        {
            ret[++count] = T::values[i];
        }

    return ret;
}


struct myset
{
    static constexpr auto values = remove_duplicates<sorted>();
};

int main ( ) {


    for ( auto i : sorted::values )
        std::cout << i << ' ';

    std::cout << std::endl;

    for ( auto i : myset::values )
        std::cout << i << ' ';
    std::cout << std::endl;

    return EXIT_SUCCESS;
}
StefanKssmr
  • 1,196
  • 9
  • 16
  • 1
    We now (since C++14) have `std::index_sequence` to replace `num_tuple`. – Jarod42 May 14 '20 at 07:23
  • Yes, you're right. Good hint. As I wrote, this was more a copy and past job, so I only checked whether it worked but did not further improve the code. – StefanKssmr May 14 '20 at 07:55
  • Your code printed repeated numbers. Nicely sorted and constexpr but not a set. –  May 19 '20 at 18:01
  • @FrankPuck Yes your right. I already pointed the out in the remark in the end: "However, you need to add some functionality which removes duplicates from the combined array to have a proper enumeration." I guess I wrote that answer before you updated your question. – StefanKssmr May 19 '20 at 18:07
  • 1
    @FrankPuck I updated my answer, now the duplicates are removed. – StefanKssmr May 19 '20 at 18:59