C++ calculate and sort vector at compile time
This is a simple compile time sort for ints. It works by for each element, working out its position within the list. From this it works out what should be at each position. Then it builds a new list inserted at the appropriate positions. It's probably not as efficient in terms of complexity (it's O(n^2)) as the previous solution but it's much easier to understand and it doesn't use recursion.
#include <initializer_list>
#include <array>
#include <tuple>
template<int... members>
struct IntList
{
constexpr bool operator==(IntList) const { return true; }
template<int... others>
constexpr bool operator==(IntList<others...>) const { return false; }
template<int idx>
static constexpr auto at()
{
return std::get<idx>(std::make_tuple(members...));
}
template<int x>
static constexpr auto indexOf()
{
int sum {};
auto _ = { 0, (x > members ? ++sum : 0)... };
return sum;
}
template<int x>
static constexpr auto count()
{
int sum {};
auto _ = { 0, (x == members ? ++sum : 0)... };
return sum;
}
template<int i>
static constexpr auto ith()
{
int result{};
auto _ = {
( i >= indexOf<members>() && i < indexOf<members>() + count<members>() ?
result = members : 0 )...
};
return result;
}
template<std::size_t... i>
static constexpr auto sortImpl(std::index_sequence<i...>)
{
return IntList< ith<i>()... >();
}
static constexpr auto sort()
{
return sortImpl(std::make_index_sequence<sizeof...(members)>());
}
};
static_assert(IntList<1, 2, 3>().at<1>() == 2, "");
static_assert(IntList<>().indexOf<1>() == 0, "");
static_assert(IntList<1>().indexOf<1>() == 0, "");
static_assert(IntList<1, 2, 3, 4>().indexOf<3>() == 2, "");
static_assert(IntList<>().count<1>() == 0, "");
static_assert(IntList<1>().count<1>() == 1, "");
static_assert(IntList<1, 1>().count<1>() == 2, "");
static_assert(IntList<2, 2, 1>().count<1>() == 1, "");
static_assert(IntList<1, 2, 1>().count<1>() == 2, "");
static_assert(IntList<>().sort() == IntList<>(), "");
static_assert(IntList<1>().sort() == IntList<1>(), "");
static_assert(IntList<1, 2>().sort() == IntList<1, 2>(), "");
static_assert(IntList<2, 1>().sort() == IntList<1, 2>(), "");
static_assert(IntList<3, 2, 1>().sort() == IntList<1, 2, 3>(), "");
static_assert(IntList<2, 2, 1>().sort() == IntList<1, 2, 2>(), "");
static_assert(IntList<4, 7, 2, 5, 1>().sort() == IntList<1, 2, 4, 5, 7>(), "");
static_assert(IntList<4, 7, 7, 5, 1, 1>().sort() == IntList<1, 1, 4, 5, 7, 7>(), "");
A std::vector<int>
does not have any constexpr
constructors (because dynamic memory allocation is disallowed for constexpr
). So you can't sort a std::vector<int>
at compile-time.
You can create a std::array<int, N>
at compile-time for a constant N
, but you'd have to write your own sorting routine because std::sort
is not constexpr
either.
You can also write a Boost.MPL compile-time vector or list and use the sort
routine of that. But this won't scale as well as std::array
.
Another angle of attack might be to store the vector into a static
variable and do the sorting at program initialization. Your program just takes a bit longer to start, but it won't affect the rest of its main functionality.
Since sorting is O(N log N)
, you might even have a two-step build and write the sorted vector to a file, and either compile/link it to your main program, or load it in O(N)
at program startup into a static
variable.