Search code examples
c++std

c++20 std::integral_constant?


I'm just into metaprogramming and was watching Cppcon channel on youtube, and saw this std::integral_constant, but cannot find its use.

As far as i understood, it is a way to "pack" a value along with its type, it can be instantiated with

std::integral_constant<int, 42> i;
std::integral_constant<bool, true> b;
std::integral_constant<float, 3.14> f;
...

and each of those instances can be used just like the value they contains, i.e.: can be passed around, used in math operations, comparisons, etc.

But i cannot understand why should i use those structs instead of the actual contained values, nor if i can actually access the value type (i.e.: int, bool and float) at runtime to do stuff with it.

Can someone present a simple example of practical use of this feature? An example that explain its usage difference from using the actual values?


Solution

  • std::integral_constant is mainly used as a utility type for writing meta-programming traits, particularly by encoding a type with a type and a value. By letting a custom trait inherit from specializations of std::integral_constant we get easy, idiomatic access to a stored non-type template parameter through the static member constant value, as well as e.g. the value type of this constant via the member typedef value_type.


    Examples

    std::integral_constant could be used for, say, writing a dimensionality trait for a matrix type

    using index_t = int;
    template <index_t M, index_t N, typename S> struct mat {
      // matrix implementation
    };
    

    as

    #include <type_traits>
    
    // Default dimensionality 0.
    template <class T, typename = void>
    struct dimensionality : std::integral_constant<index_t, 0> {};
    
    template <typename S>
    struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
        : std::integral_constant<index_t, 1> {};
    
    template <index_t M, index_t N, typename S>
    struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
    
    template <class T>
    inline constexpr index_t dimensionality_v = dimensionality<T>::value;
    

    DEMO.

    However, a more common use case is to use the two helper typedefs std::true_type and std::false_type for the common case where T is bool.

    Type        Definition
    ----        ----------
    true_type   std::integral_constant<bool, true>
    false_type  std::integral_constant<bool, false>
    

    E.g. as

    #include <type_traits>
    
    struct Foo {};
    
    template <typename T>
    struct is_foo : public std::false_type {};
    
    template<>
    struct is_foo<Foo> : public std::true_type {};
    
    template<typename T>
    constexpr bool is_foo_v = is_foo<T>::value;
    
    static_assert(is_foo_v<Foo>, "");
    static_assert(!is_foo_v<int>, "");