Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare two integer sequences at compile-time?

Let's say I have a constexpr std::integer_sequence<...> object. At compile-time, I perform some operations on it, and then I want to static_assert that it is == some other std::integer_sequence<...>. Given that the integer_sequence is a type, how would I provide an overloaded constexpr bool operator== that would appropriately compare them?

A more concrete example: converting int to std::integer_sequence<char>. That is, conversion of integer to a character sequence (inspired by Peter Sommerlad's talk at CPPCon '15)

I have some function that I'm pretty confident will appropriately convert a decimal integer value less than 1000 to a 4 element character sequence:

#include <utility> // integer_sequence

template<char... t>
using char_sequence = std::integer_sequence<char, t...>;
constexpr char make_digit_char(const size_t digit, const size_t power_of_ten=1, const char zero_replacement = ' ')
{
    return char(digit>=power_of_ten?digit/power_of_ten+'0':zero_replacement);
}

template<int num>
constexpr auto int_to_char_sequence()
{
    static_assert(num < 1000, "Cannot handle integers larger than 1000!");
    //format for up to 1000
    return char_sequence<' ', 
                    make_digit_char(num,100), 
                    make_digit_char(num%100,10,num>=100?'0':' '),
                    '0' + num % 10>{};
}

However, I don't trust myself, so I want to write some tests:

static_assert(char_sequence<' ', ' ', ' ', '0'>{} == int_to_char_sequence<0>(), "failed to convert 0 to char sequence");
static_assert(char_sequence<' ', ' ', ' ', '1'>{} == int_to_char_sequence<1>(), "failed to convert 1 to char sequence");
// ...
static_assert(char_sequence<' ', '1', '1', '1'>{} == int_to_char_sequence<111>(), "failed to convert 111 to char sequence")

and also want to test !=:

// ...
static_assert(char_sequence<' ', '1', '1', '1', '2'>{} != int_to_char_sequence<111>(), " 1 1 1 2 should not be equal to 111");
static_assert(int_to_char_sequence<111>() != char_sequence<' ', '1', '1', '1', '2'>{}, " 111 should not be equal to  1 1 1 2");

So I have a few requirements for my equivalence operators:

  • The data in the sequence is stored in the type, so two character sequences are fundamentally different types
  • What if one character sequence is longer than the other?
  • The operators need to be constexpr so that static_assert will work
    • which means we can't do any sort of conversion to std::array and compare

How do I accomplish this?


Authors note: I did not find another post on SO that could do compile-time equality for integer sequences, so I answered my own question below. This is my own work to accomplish that, and I in no way claim it to be the optimal method. If you have a better approach, please post it as another answer and I'll accept it instead!

like image 687
AndyG Avatar asked May 20 '26 06:05

AndyG


1 Answers

Here's a shorter version:

template <char... A, char... B>
constexpr bool operator==(char_sequence<A...>, char_sequence<B...>)
{
    return std::is_same<char_sequence<A...>, char_sequence<B...>>::value;
}

The sequences are the same if and only if the types composed of those sequences are the same.


Though typically, you'd just test this directly:

template <int num>
using int_to_char_sequence_t = decltype(int_to_char_sequence<num>());

static_assert(std::is_same<
    int_to_char_sequence_t<0>,
    char_sequence<' ', ' ', ' ', '0'>
    >::value, "!");
like image 119
Barry Avatar answered May 21 '26 19:05

Barry



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!