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.