Search code examples
c++templatesc++20type-traitsc++-concepts

Why is std::is_const_v evaluated to false here?


According to cppreference:

If T is a reference type then is_const<T>::value is always false. The proper way to check a potentially-reference type for const-ness is to remove the reference: is_const<typename remove_reference<T>::type>.

That makes sense for references, because there are no const references, there may only be a reference to a constant. But that should not be the case for pointers as they, unlike references, can be const. What if I want to check if a template parameter is a const pointer to a const type?

template<typename T>
requires std::is_pointer_v<T> // Ok
         && std::is_const_v<std::remove_pointer_t<T>> // Ok
         // && std::is_const_v<T> // Fails (2)
void foo(T t) { std::cout << *t << '\n'; }

int main()
{
    const int i{5};
    const int* const p{&i};

    static_assert(std::is_const_v<std::remove_pointer_t<decltype(p)>>); // Ok
    static_assert(std::is_const_v<decltype(p)>); // Ok (1)

    foo(p);
}

Something is wrong here - constraint (2) is evaluated to false. But at the same time static_assert() (1) is evaluated to true. Why is that? Is it somehow related to template parameter deduction?


Solution

  • First things first, T is deduced to be const int* for the call foo(p).


    Something is wrong here - constraint (2) is evaluated to false. But at the same time static_assert() (1) is evaluated to true. Why is that?

    Because std::is_const_v checks for a top-level const but const int* has a low-level const(not a top-level const).

    On the other hand, decltype(p) is const int* const which has a top-level const which is what std::is_const_v checks.