c++c++-conceptsc++23generic-constraintsint128

C++-23 generic constraints of specific types


I would like to build a generic constraints of 128-bit data types in GNU C++-23 for template class and/or functions. Specifically, __int128 and unsigned __int128.

How do I achieve that? I know a bit of concept.

I can use something like if constexpr (is_same_v<V, __int128>) in the class / function body but that doesn't build a generic template for that types.


Solution

  • You can make your code even more generic than what you showed in the posted answer:

    You can have a concept for specifying any size for an integral type, and then define the concept for 128 bits based on it.

    Usage can be done either in an "explicit" template (f1 below), or an "implicit" one (f2 below) - as @DanielLangr commented below.

    Note that when the concept is used in f1 / f2, there is no need for a requires clause: you can constrain the type for T with the concept is_128_bits directly where T is declared.

    #include <iostream>
    #include <type_traits>
    
    // A generic size concept:
    template <typename T, size_t num_bits>
    concept is_num_bits = std::is_integral_v<T> && ((sizeof(T) * 8) == num_bits);
    
    // A size concept for 128 bit:
    template <typename T>
    concept is_128_bits = is_num_bits<T, 128>;
    
    // You can add more sizes, e.g. 64 bits:
    template <typename T>
    concept is_64_bits = is_num_bits<T, 64>;
    
    // Usage 1: "explicit" template:
    template <is_128_bits T>
    void f1([[maybe_unused]] T val) {
        std::cout << "f1: I am " << sizeof(val) * 8 << " bits\n";
    }
    
    // Usage 2: "implicit" template with `auto` keyword:
    void f2([[maybe_unused]] is_128_bits auto val) {
        std::cout << "f2: I am " << sizeof(val) * 8 << " bits\n";
    }
    
    int main() {
        f1((__int128)5);
        f2((__int128)5);
    }
    

    Output:

    f1: I am 128 bits
    f2: I am 128 bits
    

    Live demo