2

What should I do to check whether an integer array is palindrome (e.g. 1 3 10 3 1 is palindrome) in compile time?

A possible framework could be:

template <int...>
class IntArray;

template <int... values>
class Palindrome<IntArray<values...>>;

static_assert(Palindrome<IntArray<1, 2, 1>>::check == true);

I know this question seems to be meaningless but I'm just curious about the grammar that I should use.

I've read posts and blogs about compile-time Fibonacci calculation but found nothing inspiring.

Could anyone tell me how to implement this?

I know little about compile-time programming; the most complicated problem that I can tackle with compile-time programming is like this:

template<int a, int b>
struct max_template {
    static constexpr int value = a > b ? a : b;
};

constexpr int max_fun(int a, int b) {
    return a > b ? a : b;
}

// or

template <unsigned N>
struct Fibonacci
{
    enum
    {
        value = Fibonacci<N-1>::value + Fibonacci<N-2>::value
    };
};

template <>
struct Fibonacci<1>
{
    enum
    {
        value = 1
    };
};

template <>
struct Fibonacci<0>
{
    enum
    {
        value = 0
    };
};
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
27rabbit
  • 61
  • 6

1 Answers1

7

It's more or less trivial in C++17 unless you have a limitation to use purely functional constructs:

template<int...>
class IntArray;

template<class>
struct IsPalindrome;

template<int... values>
struct IsPalindrome<IntArray<values...>> {
    static constexpr bool value = []{
        constexpr int arr[] = {values...};
        constexpr std::size_t N = std::size(arr);
        for (std::size_t i = 0; i < N / 2; ++i)
            if (arr[i] != arr[N - 1 - i])
                return false;
        return true;
    }();
};

static_assert( IsPalindrome<IntArray<0, 1, 2, 3, 2, 1, 0>>::value);
static_assert(!IsPalindrome<IntArray<0, 1, 2, 3, 4, 1, 0>>::value);

Purely functional implementation is more lengthy but works even in C++11:

template<class IntArray, int>
struct PushBack;

template<int... values, int value>
struct PushBack<IntArray<values...>, value> {
    using type = IntArray<values..., value>;
};

template<class IntArray>
struct Reverse;

template<>
struct Reverse<IntArray<>> {
    using type = IntArray<>;
};

template<int first, int... rest>
struct Reverse<IntArray<first, rest...>> {
    using type = typename PushBack<
        typename Reverse<IntArray<rest...>>::type, 
        first
    >::type;
};

template<class IntArray>
using IsPalindrome = 
    std::is_same<IntArray, typename Reverse<IntArray>::type>;
Evg
  • 25,259
  • 5
  • 41
  • 83
  • Thanks so much. Seems that I need to learn more about C++17 grammar! – 27rabbit Aug 19 '23 at 14:45
  • 2
    @27rabbit Added a purely functional implementation, like that of `Fibonacci`. – Evg Aug 19 '23 at 14:58
  • 1
    You could shorten this slightly be inheriting from `std::bool_constant` instead of defining a `static constexpr bool` member. Also, you can use `std::integer_sequence`. – Jan Schultke Aug 19 '23 at 20:06